趁着UI妹子还没有把图切好,我这几天简直闲得不行,所以得空学习一下CoordinatorLayout
的使用,当然这里不会是想特地写一篇文章来介绍它的基本用法,因为这个在网上有太多的资料。学习完基础我们就可以深入其中,学习其精髓。那么CoordinatorLayout
最精髓的地方是什么呢?就是Behaviour。
那么什么是Behaviour呢?可以先看看以下博客
Android——CoordinatorLayout之Behavior入门学习(上)
Android——CoordinatorLayout之Behavior入门学习(下)
感谢博主郭神。
Behaviour使用
一、仿知乎首页
项目中将会使用到知乎首页的效果
我们可以看到,底部菜单Tab会随着滑动隐藏和显示
不使用Behaviour
我在第一次思考时是不使用Behaviour,监听AppBarLayout滑动距离进行操作:
bar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
///下拉:0~-height,上拉:-height~0
if (verticalOffset != 0) {
if (height != 0) {
Log.d("Activity", "onOffsetChanged: vertaicalOffset =====" + verticalOffset);
//通过滑动距离跟高度计算得到percent值
float i = (height + verticalOffset) / height;
Log.d("Activity", "onOffsetChanged: i=====" + i);
float alpha = 255 * i / 255;
Log.d("Activity", "onOffsetChanged: alpha === " + alpha);
ViewGroup.LayoutParams params = mBottom.getLayoutParams();
//通过percent值对底部Tab的LayoutParams进行修改
params.height = (int) (height * alpha);
mBottom.requestLayout();
}
}
}
});```
这时我遇到一个小问题,就是在快速滑动的时候底部Tab计算会跟不上滑动的速度导致底部Tab的高度不正确
(如下图)
![error](http://upload-images.jianshu.io/upload_images/2605454-50d04a033b273dca.gif?imageMogr2/auto-orient/strip)
那么我是怎样解决的呢?
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
Log.d("Activity", "onScrollStateChanged: newState===" + newState);
// LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int position = layoutManager.findFirstCompletelyVisibleItemPosition();
Log.d("Activity", "onScrollStateChanged: completeItemPosition ====" + position);
if (position == 0 && newState == RecyclerView.SCROLL_STATE_IDLE) {
if (mBottom.getHeight() != height) {
mBottom.getLayoutParams().height = (int) height;
mBottom.requestLayout();
}
}
}
});```
我这里是通过监听recyclerView的显示item来强制修改,达到目的(这里提供一个解决思路,非最佳)
使用Behaviour
简单自定义一个Behaviour即可达到效果
/**
* Created by AmatorLee on 2017/7/18.
*/
public class FootBehaviour extends CoordinatorLayout.Behavior {
public FootBehaviour(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
//通过AppBarLayout的滑动距离计算percent
float scaleY = Math.abs(dependency.getY()) / dependency.getHeight();
//通过percent动态移动我们的view,注意是移动不是修改
child.setTranslationY(child.getHeight() * scaleY);
return true;
}
}```
看看效果
![success](http://upload-images.jianshu.io/upload_images/2605454-d2c1dd241203bd1b.gif?imageMogr2/auto-orient/strip)
#####二、仿魅族应用商店应用详情效果
作为一个多年的魅族手机使用者,看起来魅族的应用商店也挺不错的,来看看要实现的效果(**注:实现效果而非实现实现界面**)
![sheet](http://upload-images.jianshu.io/upload_images/2605454-3b9fc78ca7aaaa87.gif?imageMogr2/auto-orient/strip)
1. 思路一:使用Activity实现,但是这样需要解决的问题有:
1. Activity进场/出场动画
2. 对于滑动的监听
3. 对状态栏的动态改变
2. 思路二:由于我们这边使用的是Behaviour,而系统给我们提供了一个```BottomSheetBehavior```应该可以完美的给我们解决滑动的问题,但是Activity方面的问题依然存在,然后找到了一个强大的Dialog(```BottomSheetDialog```)和一个DialogFragment(```BottomSheetDialogFragment```),,以我夜观天象应该这个就是实现了``````BottomSheetBehavior```的View,很好很强大。
我们来看看我们是怎样是实现的:
/**
* BottomSheetDialog
*/
Button btnShowDialog = (Button) findViewById(R.id.bottom_pull_sheet);
mDatas = new ArrayList<>();
View inflate = getLayoutInflater().inflate(R.layout.dialog_bottom_sheet, null);
mLeftIcon = inflate.findViewById(R.id.delete);
mLeftIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mBottomSheetDialog != null && mBottomSheetDialog.isShowing()) {
mBottomSheetDialog.dismiss();
}
}
});
RecyclerView recyclerView = inflate.findViewById(R.id.recyclerView);
mDatas = new ArrayList<>();
for (int i = 0; i < 50; i++) {
mDatas.add("这是第" + i + "个数据");
}
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
Adapter adapter = new Adapter();
recyclerView.setAdapter(adapter);
mBottomSheetDialog = new BottomSheetDialog(this);
mBottomSheetDialog.setContentView(inflate);
View container = mBottomSheetDialog.getDelegate().findViewById(android.support.design.R.id.design_bottom_sheet);
final BottomSheetBehavior containerBehaviour = BottomSheetBehavior.from(container);
containerBehaviour.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
Log.d(TAG, "onStateChanged: newState === " + newState);
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
mBottomSheetDialog.dismiss();
containerBehaviour.setState(BottomSheetBehavior.STATE_COLLAPSED);
} else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
//强制修改弹出高度为屏幕高度的0.9倍,不做此操作仅仅有CollapSed/Expand两种,就是0.5和1倍展开的效果
containerBehaviour.setPeekHeight((int) (0.9 * height));
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
Log.d("BottomBahaviour", "onSlide: slideOffset====" + slideOffset);
if (slideOffset == 1.0) {
mLeftIcon.setImageResource(R.drawable.back);
// containerBehaviour.setPeekHeight(height + getStatusBarHeight());
//修改状态栏
mBottomSheetDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mBottomSheetDialog.getWindow().setStatusBarColor(getResources().getColor(android.R.color.transparent));
try {
//修改魅族系统状态栏字体颜色
WindowManager.LayoutParams lp = mBottomSheetDialog.getWindow().getAttributes();
Field darkFlag = WindowManager.LayoutParams.class
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class
.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
value |= bit;
meizuFlags.setInt(lp, value);
mBottomSheetDialog.getWindow().setAttributes(lp);
} catch (Exception e) {
}
}
} else {
mLeftIcon.setImageResource(R.drawable.icon_delete);
}
}
});
btnShowDialog.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!mBottomSheetDialog.isShowing()) {
containerBehaviour.setPeekHeight((int) (0.9 * height));
mBottomSheetDialog.show();
} else {
mBottomSheetDialog.dismiss();
}
}
});
class Adapter extends RecyclerView.Adapter
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(BottomActivity.this).inflate(R.layout.layout_item, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.mTvTip.setText(mDatas.get(position));
}
@Override
public int getItemCount() {
return mDatas == null && mDatas.size() < 0 ? 0 : mDatas.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView mTvTip;
public ViewHolder(View itemView) {
super(itemView);
mTvTip = (TextView) itemView.findViewById(R.id.tv_tips);
}
}
}
通过以上简单的错作即可实现我们想要的效果:
![pullSheet](http://upload-images.jianshu.io/upload_images/2605454-a1bcc209a0eba14f.gif?imageMogr2/auto-orient/strip)
这是在模拟器上运行的结果,在魅族手机呢?
![meizu](http://upload-images.jianshu.io/upload_images/2605454-ee040385cd582da2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
就这么简单即可完美实现效果。
#####总结
通过对Behaviour的学习很多看起来以前很难的效果我们都可以轻松实现。如果你发现上面有任何错漏,麻烦留言指出,同时我也会进行自我完善。
#####参考文章
[白底黑字!Android浅色状态栏黑色字体模式](http://www.jianshu.com/p/7f5a9969be53)
[Material Design系列](http://blog.csdn.net/yanzhenjie1003/article/details/52205665)