Android 带有自定义视图的 CollapsingToolbarLayout
Android CollapsingToolbarLayout with custom View
我正在关注 Cheesesquare 示例项目以了解新设计 material 库。
我想知道是否有办法使用带有 ImageView、标题和副标题的自定义视图(如 Telegram),而不是 CollapsingToolbarLayout 小部件提供的简单标题。
谢谢。
从小部件本身来看,似乎没有办法直接启用它,就像可以将自定义视图添加到工具栏一样。
然而,您可以尝试做的是打开 CollapsingToolbarLayout.class
的源代码并查看 CollapsingTextHelper.class
是如何用于设置标题的。您可以尝试通过从 CollapsingToolbarLayout
扩展来制作您自己的小部件。
这些链接可以帮助您创建自定义 components/views,如果您之前没有创建过它们:
Custom Views, Custom Components
我还没有尝试过,但实际上我正在考虑尝试实现与您正在寻找的类似的解决方案。到目前为止我想遵循的步骤:
- 在
attrs.xml
中为字幕设置创建自定义属性
- 通过扩展原始文件创建您自己的
MyCollapsingToolbarLayout
。
- 确保在构造函数中调用
super
,这样原始组件将保持完整。
- 通过向您的组件添加新的
CollapsingTextHelper
创建一个 subtitleTextHelper
。
- 覆盖
onDraw
以实际绘制字幕。
- 使用字幕属性(默认样式等,可能是固定的字幕文本)更新包含
CollapingsToolbarLayout
的布局。
- 在包含您的
CollapsingToolbar
的 Activity
中应用更改。 (将 CollapsingToolbarlayout
转换为 MyCollapingsToolbarLayout
、设置字幕、额外的自定义设置等)。
- 十指交叉,测试。
现在就去看看。
我遇到了同样的问题,花了很多时间试图找到解决方案。我的解决方案是在 CollapsingToolbarLayout
中添加折叠视图(ImageView 和 TextView),然后在代码中处理转换。这种方式比从 CollapsingToolbarLayout 扩展更灵活、更简单。
首先,您需要在 CollapsingToolbarLayout
中添加具有视差属性的视图:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop:"80dp"
android:src="@drawable/icon"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here
然后在 OnOffsetchangeListner
:
的帮助下设置视图的缩放比例
private static final float SCALE_MINIMUM=0.5f;
appBarLayout.setOnWorkingOffsetChange(new ControllableAppBarLayout.OnWorkingOffsetChange() {
@Override
public void onOffsetChange(int offSet, float collapseDistance) {
imageView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
imageView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));
textView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
textView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));
// You can also setTransitionY/X, setAlpha, setColor etc.
}
});
默认的 offsetChangedListener
对我来说无法正常工作(您可能仍然应该先尝试使用默认的侦听器),所以我使用了 https://gist.github.com/blipinsk/3f8fb37209de6d3eea99 中的 ControllableAppBarLayout
和添加了以下内容:
private OnWorkingOffsetChange onWorkingOffsetChange;
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
if (!isInEditMode()) {
onWorkingOffsetChange.onOffsetChange(i, (float) i / appBarLayout.getTotalScrollRange());
}
}
public void setOnWorkingOffsetChange(OnWorkingOffsetChange listener) {
this.onWorkingOffsetChange = listener;
}
public interface OnWorkingOffsetChange {
void onOffsetChange(int offSet, float collapseDistance);
}
唯一的问题是,您需要设置
app:contentScrim="#00000000"
(透明)
对于您的 CollapsingToolbarLayout
,因此当工具栏折叠时您的视图仍然可见。如果你真的需要折叠背景效果,我相信你可以 "fake" 通过在 OffsetChangeListener
中设置背景 ImageView 的 alpha 来做到这一点。 ;)
要稍微编辑 Christopher 的回答以展示如何让自定义视图在折叠时不消失:
首先,您需要在 CollapsingToolbarLayout
中添加具有视差属性的视图:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop:"80dp"
android:src="@drawable/icon"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here
而是以编程方式添加自定义视图,它不会在折叠时消失。例如,这里是一个包含标题和副标题的视图:
final FrameLayout frameLayout = new FrameLayout(mActivity);
FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
frameLayout.setLayoutParams(frameLayoutParams);
// Create new LinearLayout
final LinearLayout linearLayout = new LinearLayout(mActivity);
frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
frameLayoutParams.gravity = Gravity.BOTTOM;
linearLayout.setLayoutParams(frameLayoutParams);
linearLayout.setOrientation(LinearLayout.VERTICAL);
// Add textviews
final TextView textView1 = new TextView(mActivity);
LinearLayout.LayoutParams linearLayoutParams =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
frameLayoutParams.gravity = Gravity.BOTTOM;
textView1.setLayoutParams(linearLayoutParams);
textView1.setText("Title");
textView1.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
textView1.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40);
linearLayout.addView(textView1);
final TextView textView2 = new TextView(mActivity);
linearLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
textView2.setLayoutParams(linearLayoutParams);
textView2.setText("Subtitle");
textView2.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
textView2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
linearLayout.addView(textView2);
frameLayout.addView(linearLayout);
collapsingToolbar.addView(frameLayout);
final float SCALE_MIN=0.4f;
AppBarLayout appBarLayout = (AppBarLayout) mActivity.findViewById(R.id.appBarLayout);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offSet) {
float collapsedRatio = (float) offSet / appBarLayout.getTotalScrollRange();
linearLayout.setScaleX(1 + (collapsedRatio * SCALE_MIN));
linearLayout.setScaleY(1 + (collapsedRatio * SCALE_MIN));
FrameLayout.LayoutParams frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
frameLayoutParams.gravity = Gravity.BOTTOM;
frameLayoutParams.setMargins(Math.round(dpToPixels(48) * (1+collapsedRatio)), 0, 0, Math.round(dpToPixels(15) * collapsedRatio));
linearLayout.setLayoutParams(frameLayoutParams);
// You can also setTransitionY/X, setAlpha, setColor etc.
}
});
/////
float lastCollapsedRatio = -2;
////
private int dpToPixels(int padding_in_dp){
final float scale = getResources().getDisplayMetrics().density;
int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
return padding_in_px;
}
我正在关注 Cheesesquare 示例项目以了解新设计 material 库。
我想知道是否有办法使用带有 ImageView、标题和副标题的自定义视图(如 Telegram),而不是 CollapsingToolbarLayout 小部件提供的简单标题。
谢谢。
从小部件本身来看,似乎没有办法直接启用它,就像可以将自定义视图添加到工具栏一样。
然而,您可以尝试做的是打开 CollapsingToolbarLayout.class
的源代码并查看 CollapsingTextHelper.class
是如何用于设置标题的。您可以尝试通过从 CollapsingToolbarLayout
扩展来制作您自己的小部件。
这些链接可以帮助您创建自定义 components/views,如果您之前没有创建过它们: Custom Views, Custom Components
我还没有尝试过,但实际上我正在考虑尝试实现与您正在寻找的类似的解决方案。到目前为止我想遵循的步骤:
- 在
attrs.xml
中为字幕设置创建自定义属性
- 通过扩展原始文件创建您自己的
MyCollapsingToolbarLayout
。 - 确保在构造函数中调用
super
,这样原始组件将保持完整。 - 通过向您的组件添加新的
CollapsingTextHelper
创建一个subtitleTextHelper
。 - 覆盖
onDraw
以实际绘制字幕。 - 使用字幕属性(默认样式等,可能是固定的字幕文本)更新包含
CollapingsToolbarLayout
的布局。 - 在包含您的
CollapsingToolbar
的Activity
中应用更改。 (将CollapsingToolbarlayout
转换为MyCollapingsToolbarLayout
、设置字幕、额外的自定义设置等)。 - 十指交叉,测试。
现在就去看看。
我遇到了同样的问题,花了很多时间试图找到解决方案。我的解决方案是在 CollapsingToolbarLayout
中添加折叠视图(ImageView 和 TextView),然后在代码中处理转换。这种方式比从 CollapsingToolbarLayout 扩展更灵活、更简单。
首先,您需要在 CollapsingToolbarLayout
中添加具有视差属性的视图:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop:"80dp"
android:src="@drawable/icon"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here
然后在 OnOffsetchangeListner
:
private static final float SCALE_MINIMUM=0.5f;
appBarLayout.setOnWorkingOffsetChange(new ControllableAppBarLayout.OnWorkingOffsetChange() {
@Override
public void onOffsetChange(int offSet, float collapseDistance) {
imageView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
imageView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));
textView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
textView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));
// You can also setTransitionY/X, setAlpha, setColor etc.
}
});
默认的 offsetChangedListener
对我来说无法正常工作(您可能仍然应该先尝试使用默认的侦听器),所以我使用了 https://gist.github.com/blipinsk/3f8fb37209de6d3eea99 中的 ControllableAppBarLayout
和添加了以下内容:
private OnWorkingOffsetChange onWorkingOffsetChange;
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
if (!isInEditMode()) {
onWorkingOffsetChange.onOffsetChange(i, (float) i / appBarLayout.getTotalScrollRange());
}
}
public void setOnWorkingOffsetChange(OnWorkingOffsetChange listener) {
this.onWorkingOffsetChange = listener;
}
public interface OnWorkingOffsetChange {
void onOffsetChange(int offSet, float collapseDistance);
}
唯一的问题是,您需要设置
app:contentScrim="#00000000"
(透明)
对于您的 CollapsingToolbarLayout
,因此当工具栏折叠时您的视图仍然可见。如果你真的需要折叠背景效果,我相信你可以 "fake" 通过在 OffsetChangeListener
中设置背景 ImageView 的 alpha 来做到这一点。 ;)
要稍微编辑 Christopher 的回答以展示如何让自定义视图在折叠时不消失:
首先,您需要在 CollapsingToolbarLayout
中添加具有视差属性的视图:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop:"80dp"
android:src="@drawable/icon"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here
而是以编程方式添加自定义视图,它不会在折叠时消失。例如,这里是一个包含标题和副标题的视图:
final FrameLayout frameLayout = new FrameLayout(mActivity);
FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
frameLayout.setLayoutParams(frameLayoutParams);
// Create new LinearLayout
final LinearLayout linearLayout = new LinearLayout(mActivity);
frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
frameLayoutParams.gravity = Gravity.BOTTOM;
linearLayout.setLayoutParams(frameLayoutParams);
linearLayout.setOrientation(LinearLayout.VERTICAL);
// Add textviews
final TextView textView1 = new TextView(mActivity);
LinearLayout.LayoutParams linearLayoutParams =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
frameLayoutParams.gravity = Gravity.BOTTOM;
textView1.setLayoutParams(linearLayoutParams);
textView1.setText("Title");
textView1.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
textView1.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40);
linearLayout.addView(textView1);
final TextView textView2 = new TextView(mActivity);
linearLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
textView2.setLayoutParams(linearLayoutParams);
textView2.setText("Subtitle");
textView2.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
textView2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
linearLayout.addView(textView2);
frameLayout.addView(linearLayout);
collapsingToolbar.addView(frameLayout);
final float SCALE_MIN=0.4f;
AppBarLayout appBarLayout = (AppBarLayout) mActivity.findViewById(R.id.appBarLayout);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offSet) {
float collapsedRatio = (float) offSet / appBarLayout.getTotalScrollRange();
linearLayout.setScaleX(1 + (collapsedRatio * SCALE_MIN));
linearLayout.setScaleY(1 + (collapsedRatio * SCALE_MIN));
FrameLayout.LayoutParams frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
frameLayoutParams.gravity = Gravity.BOTTOM;
frameLayoutParams.setMargins(Math.round(dpToPixels(48) * (1+collapsedRatio)), 0, 0, Math.round(dpToPixels(15) * collapsedRatio));
linearLayout.setLayoutParams(frameLayoutParams);
// You can also setTransitionY/X, setAlpha, setColor etc.
}
});
/////
float lastCollapsedRatio = -2;
////
private int dpToPixels(int padding_in_dp){
final float scale = getResources().getDisplayMetrics().density;
int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
return padding_in_px;
}