xml地图|网站地图|网站标签 [设为首页] [加入收藏]

智能家电

当前位置:美高梅游戏网站 > 智能家电 > 仿Moto佐藤浩市应用集团应用详细情况页效果

仿Moto佐藤浩市应用集团应用详细情况页效果

来源:http://www.gd-chuangmei.com 作者:美高梅游戏网站 时间:2019-09-08 03:06

效果视频工作中需要实现类似360手机助手的游戏详情页上滚动效果,花了1天的时间研究了下,实现出来了.记录下.拿到效果后用uiautomatorviewer工具窥探了下360的实现方式,发现它是用RecycleView实现的,那么要实现这种效果估计就是通过自定义LayoutManager来实现的了.视频中每一张图片缩小为一个点,然后可以看成是点沿着一个圆弧运动.自定义LayoutManager将不同的item根据index放到位于圆弧的相应位置.思考到之前用到的PathMeasure类的使用跟自定义LayoutManager接合起来使用刚好能达到这种效果.

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

实现这种效果用到的主要知识点

Behaviour使用

1.自定义LayoutManager 2.Path,PathMeasure系列Api的运用

一、仿知乎首页

项目中将会使用到知乎首页的效果

zhihu

我们可以看到,底部菜单Tab会随着滑动隐藏和显示

 RectF rectF=new RectF(0,dp2px,screenWidth,dp2px;//第2个和第 path.addArc(rectF,0,-180); //添加一个逆时针180度的弧度,从3点钟方向为起点 pathMeasure.setPath(path,false); //注意次处要设置为false,否则pathMeasure.getLength,返回的长度包括封闭扇形的2条半径
不使用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来强制修改,达到目的(这里提供一个解决思路,非最佳)

PathMeasure的getPosTan方法,通过传入在path的length范围内的值,然后计算出相应位置和角度值分别放到了pos数组和tan数组里面.

使用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)

本文由美高梅游戏网站发布于智能家电,转载请注明出处:仿Moto佐藤浩市应用集团应用详细情况页效果

关键词: