Android CollapsingToolbarLayout 折叠监听器
Posted
技术标签:
【中文标题】Android CollapsingToolbarLayout 折叠监听器【英文标题】:Android CollapsingToolbarLayout collapse Listener 【发布时间】:2015-10-19 08:43:09 【问题描述】:我正在使用CollapsingToolBarLayout
以及AppBarLayout
和CoordinatorLayout
,它们完全可以正常工作。我将我的Toolbar
设置为在向上滚动时固定,我想知道是否有办法更改工具栏的标题文本,当 CollapsingToolBarLayout
它被折叠时。
总结一下,当滚动和展开时,我想要两个不同的标题。
提前谢谢大家
【问题讨论】:
【参考方案1】:将OnOffsetChangedListener
连接到您的AppBarLayout
。当verticalOffset
达到0或小于Toolbar
高度时,说明CollapsingToolbarLayout已经折叠,否则正在展开或展开。
mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener()
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
if(verticalOffset == 0 || verticalOffset <= mToolbar.getHeight() && !mToolbar.getTitle().equals(mCollapsedTitle))
mCollapsingToolbar.setTitle(mCollapsedTitle);
else if(!mToolbar.getTitle().equals(mExpandedTitle))
mCollapsingToolbar.setTitle(mExpandedTitle);
);
【讨论】:
它对我不起作用。 OnCollapse 我想启用主页按钮并在展开时隐藏主页按钮 工具栏完全展开时,verticalOffset 值似乎为零,然后在折叠时变为负数。当工具栏收起时,verticalOffset 等于工具栏高度的负数 (-mToolbar.getHeight())。所以...工具栏部分展开“if (verticalOffset > -mToolbar.getHeight())” 如果有人想知道appBarLayout.getVerticalOffset()
方法在哪里,您可以调用appBarLayout.getY()
来检索回调中使用的相同值。
不幸的是,Jarett Millard 不对。根据您的 fitSystemWindow 配置和 StatusBar 配置(透明)appBarLayout.getY()
可能是 verticalOffset = appBarLayout.getY() + statusBarHeight
有没有人注意到即使我们实际上并没有与 appbar 交互,是否会重复调用 mAppBarLayout.addOnOffsetChangedListener(listener)?或者这是我观察到这种行为的布局/应用程序中的一个错误。请帮忙!【参考方案2】:
这个解决方案对我有用:
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i)
if (i == 0)
if (onStateChangeListener != null && state != State.EXPANDED)
onStateChangeListener.onStateChange(State.EXPANDED);
state = State.EXPANDED;
else if (Math.abs(i) >= appBarLayout.getTotalScrollRange())
if (onStateChangeListener != null && state != State.COLLAPSED)
onStateChangeListener.onStateChange(State.COLLAPSED);
state = State.COLLAPSED;
else
if (onStateChangeListener != null && state != State.IDLE)
onStateChangeListener.onStateChange(State.IDLE);
state = State.IDLE;
在 AppBarLayout 上使用 addOnOffsetChangedListener。
【讨论】:
你能分享你的完整代码吗?什么是 State.EXPANDED 等?【参考方案3】:private enum State
EXPANDED,
COLLAPSED,
IDLE
private void initViews()
final String TAG = "AppBarTest";
final AppBarLayout mAppBarLayout = findViewById(R.id.appbar);
mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener()
private State state;
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
if (verticalOffset == 0)
if (state != State.EXPANDED)
Log.d(TAG,"Expanded");
state = State.EXPANDED;
else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange())
if (state != State.COLLAPSED)
Log.d(TAG,"Collapsed");
state = State.COLLAPSED;
else
if (state != State.IDLE)
Log.d(TAG,"Idle");
state = State.IDLE;
);
【讨论】:
【参考方案4】:我分享基于@Frodio Beggins 和@Nifhel 代码的完整实现:
public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener
public enum State
EXPANDED,
COLLAPSED,
IDLE
private State mCurrentState = State.IDLE;
@Override
public final void onOffsetChanged(AppBarLayout appBarLayout, int i)
if (i == 0)
if (mCurrentState != State.EXPANDED)
onStateChanged(appBarLayout, State.EXPANDED);
mCurrentState = State.EXPANDED;
else if (Math.abs(i) >= appBarLayout.getTotalScrollRange())
if (mCurrentState != State.COLLAPSED)
onStateChanged(appBarLayout, State.COLLAPSED);
mCurrentState = State.COLLAPSED;
else
if (mCurrentState != State.IDLE)
onStateChanged(appBarLayout, State.IDLE);
mCurrentState = State.IDLE;
public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
然后你就可以使用它了:
appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener()
@Override
public void onStateChanged(AppBarLayout appBarLayout, State state)
Log.d("STATE", state.name());
);
【讨论】:
没错。但请不要使用 Proguard 将枚举转换为整数值。 我不知道。太好了! 枚举也是确保类型安全的一种非常好的方法。您不能拥有 State.IMPLODED 因为它不存在(编译器会抱怨),但是使用整数常量,您可以使用编译器不知道是错误的值。他们也很适合单身人士,但那是另一回事了。 @droppin_science for android enums check out IntDef @DavidDarias 就我个人而言,我发现枚举是一种更简洁的方法,即使它们的开销也是如此(此处开始参数... :-)【参考方案5】:这段代码对我有用
mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener()
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
if (verticalOffset == -mCollapsingToolbarLayout.getHeight() + mToolbar.getHeight())
//toolbar is collapsed here
//write your code here
);
【讨论】:
比 Nikola Despotoski 更好的答案 似乎不是一个可靠的解决方案。我对其进行了测试,我的设备上的值如下:mCollapsingToolbarLayout.getHeight() = 1013, mToolbar.getHeight() = 224。因此根据您的解决方案,折叠状态下的垂直偏移必须为 -789,但它等于 -693 【参考方案6】:这个解决方案非常适合我检测AppBarLayout
折叠或展开。
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener()
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
if (Math.abs(verticalOffset)-appBarLayout.getTotalScrollRange() == 0)
// Collapsed
else
//Expanded
);
在AppBarLayout
上使用addOnOffsetChangedListener
。
【讨论】:
这起火灾在多个场合崩溃了,在展开时也是如此。【参考方案7】:如果你使用的是 CollapsingToolBarLayout 你可以放这个
collapsingToolbar.setExpandedTitleColor(ContextCompat.getColor(activity, android.R.color.transparent));
collapsingToolbar.setTitle(title);
【讨论】:
【参考方案8】:您可以使用以下方法获取 collapsingToolBar alpha 百分比:
appbarLayout.addOnOffsetChangedListener( new AppBarLayout.OnOffsetChangedListener()
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
float percentage = ((float)Math.abs(verticalOffset)/appBarLayout.getTotalScrollRange());
fadedView.setAlpha(percentage);
);
供参考:link
【讨论】:
这是一个很好的答案,因为它提供了一个标准化的偏移量。在我看来,API 应该直接提供这个而不是verticalOffset
像素距离。
我想当 AppBarLayout 折叠时隐藏视图并显示展开视图。所以我使用val percentage = 1 - abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange
。对我来说效果很好。【参考方案9】:
这段代码非常适合我。您可以使用百分比比例您喜欢的方式
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
double percentage = (double) Math.abs(verticalOffset) / collapsingToolbar.getHeight();
if (percentage > 0.8)
collapsingToolbar.setTitle("Collapsed");
else
collapsingToolbar.setTitle("Expanded");
【讨论】:
【参考方案10】:我的工具栏偏移值在折叠时得到 -582,在展开时=0 所以我通过在 Toast 中设置 offsetvalue 来找到价值并相应地更改代码。
mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener()
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
if(verticalOffset == -582)
Toast.makeText(MainActivity.this, "collaped" + verticalOffset, Toast.LENGTH_SHORT).show();
mCollapsingToolbarLayout.setTitle("Collapsed");
else if(verticalOffset == 0)
Toast.makeText(MainActivity.this, "expanded" + verticalOffset, Toast.LENGTH_SHORT).show();
mCollapsingToolbarLayout.setTitle("expanded");
);
【讨论】:
【参考方案11】:这是一个 Kotlin 解决方案。将OnOffsetChangedListener
添加到AppBarLayout
。
方法一:
将AppBarStateChangeListener.kt
添加到您的项目中:
import com.google.android.material.appbar.AppBarLayout
import kotlin.math.abs
abstract class AppBarStateChangeListener : AppBarLayout.OnOffsetChangedListener
enum class State
EXPANDED, COLLAPSED, IDLE
private var mCurrentState = State.IDLE
override fun onOffsetChanged(appBarLayout: AppBarLayout, i: Int)
if (i == 0 && mCurrentState != State.EXPANDED)
onStateChanged(appBarLayout, State.EXPANDED)
mCurrentState = State.EXPANDED
else if (abs(i) >= appBarLayout.totalScrollRange && mCurrentState != State.COLLAPSED)
onStateChanged(appBarLayout, State.COLLAPSED)
mCurrentState = State.COLLAPSED
else if (mCurrentState != State.IDLE)
onStateChanged(appBarLayout, State.IDLE)
mCurrentState = State.IDLE
abstract fun onStateChanged(
appBarLayout: AppBarLayout?,
state: State?
)
将监听器添加到您的appBarLayout
:
appBarLayout.addOnOffsetChangedListener(object: AppBarStateChangeListener()
override fun onStateChanged(appBarLayout: AppBarLayout?, state: State?)
Log.d("State", state.name)
when(state)
State.COLLAPSED -> /* Do something */
State.EXPANDED -> /* Do something */
State.IDLE -> /* Do something */
)
方法B:
appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener appBarLayout, verticalOffset ->
if (abs(verticalOffset) - appBarLayout.totalScrollRange == 0)
// Collapsed
else if (verticalOffset == 0)
// Expanded
else
// Idle
)
【讨论】:
【参考方案12】:这是 Kotlin 中的解决方案:
abstract class AppBarStateChangeListener : OnOffsetChangedListener
enum class State
EXPANDED, COLLAPSED, IDLE
private var mCurrentState =
State.IDLE
override fun onOffsetChanged(appBarLayout: AppBarLayout, i: Int)
mCurrentState = if (i == 0)
if (mCurrentState != State.EXPANDED)
onStateChanged(appBarLayout, State.EXPANDED)
State.EXPANDED
else if (Math.abs(i) >= appBarLayout.totalScrollRange)
if (mCurrentState != State.COLLAPSED)
onStateChanged(appBarLayout, State.COLLAPSED)
State.COLLAPSED
else
if (mCurrentState != State.IDLE)
onStateChanged(appBarLayout, State.IDLE)
State.IDLE
abstract fun onStateChanged(
appBarLayout: AppBarLayout?,
state: State?
)
这里是监听器:
appbar.addOnOffsetChangedListener(object : AppBarStateChangeListener()
override fun onStateChanged(
appBarLayout: AppBarLayout?,
state: State?
)
if(state == State.COLLAPSED)
LayoutBottom.visibility = View.GONE
else if(state == State.EXPANDED)
LayoutBottom.visibility = View.VISIBLE
)
【讨论】:
以上是关于Android CollapsingToolbarLayout 折叠监听器的主要内容,如果未能解决你的问题,请参考以下文章
CollapsingToolbar, Viewpager 有 recyclerview 和 NestedScrollview
使用 CollapsingToolbar 滚动时如何更新工具栏