仿魅族应用商店应用详情页效果

368 阅读4分钟

趁着UI妹子还没有把图切好,我这几天简直闲得不行,所以得空学习一下CoordinatorLayout的使用,当然这里不会是想特地写一篇文章来介绍它的基本用法,因为这个在网上有太多的资料。学习完基础我们就可以深入其中,学习其精髓。那么CoordinatorLayout最精髓的地方是什么呢?就是Behaviour。 那么什么是Behaviour呢?可以先看看以下博客 Android——CoordinatorLayout之Behavior入门学习(上) Android——CoordinatorLayout之Behavior入门学习(下) 感谢博主郭神。 ####Behaviour使用 #####一、仿知乎首页 项目中将会使用到知乎首页的效果

zhihu
我们可以看到,底部菜单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<View> {


    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<Adapter.ViewHolder> { @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)