学习自

http://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650824778&idx=1&sn=c7116f310e70a2403c5e5d88c724060b


学习总结:

算不上是RecyclerView的进阶使用

1.对recycler view动画的使用比较浅

2.没有重写LayoutManager

3.自动居中问题也通过自带api简单处理了

不过配合card view,让人感觉真的美爆了。


  


是这样的效果 蛮漂亮的


1.自动居中

LinearSnapHelper mLinearySnapHelper = new LinearSnapHelper();

mLinearySnapHelper.attachToRecyclerView(mGalleryRecyclerView);

自带的api舒服的一匹,不过我们采用手势判断再解决一些事件问题,也可以轻松实现

linear是允许一次滑多个

pager开头的是只允许一次滑一个


2.设置边距

他就是想让分别给第一个item和最后一个item设置不一样的边距,不显得太突兀。

实现起来很简单,可以在adapter里直接写,也可以重写一个item decoration,都很好,没有孰优孰劣,看自己喜欢


3.实现动画

3个点:获取当前是第几个item、获取偏移值、根据偏移值去设置动画

获取第几个item直接onScrollListener里就可以得到,得到的方式有多种;

获取偏移值,不用说也能知道;

设置动画,也很简单;

有个地方讲的不是太清楚,他的动画原理应该是这样的


是从左边顶部开始的,也可以是从底部开始的。我一开始有点太主观了,从中间开始考虑起来,耽误了一会。


4.高斯模糊

直接调用算法即可

效果



5.淡入淡出

高斯图切换的太过突兀,所以需要淡入淡出。用一个比较厉害的drawable::TransitionDrawable

用法你一看就能明白

private void setBlurImage(RelativeLayout bg) {    int position = s.getPosition();    Drawable d = array.get(position);    if (old == null) {        bg.setBackgroundDrawable(d);    } else {        TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[]{old,d});        bg.setBackgroundDrawable(transitionDrawable);        transitionDrawable.startTransition(500);    }    old = d;}

但是有个巨坑,第一个item和最后一个item不会默认居中,所以会有一个两次的调用。比如0滑到1是ok的,但是1滑到0,会在1滑到0这个原有的基础上再进行一个滑动->0滑到0。所以判重return即可。

private Drawable old;private void setBlurImage(RelativeLayout bg) {    int position = s.getPosition();    Drawable d = array.get(position);    if (d == old) {        return;    }    if (old == null) {        bg.setBackgroundDrawable(d);    } else {        TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[]{old,d});        bg.setBackgroundDrawable(transitionDrawable);        transitionDrawable.startTransition(500);    }    old = d;}

效果



全部代码,特别清晰,加了注释,原文用了高大上的架构,我看不懂

public class Test {    private Context context;    private ScrollManager s;    private int[] res = {R.drawable.face_register,R.drawable.tmp_permission,R.drawable.village};    private final SparseArray array;    public Test(RecyclerView rv, final RelativeLayout bg) {        context = rv.getContext();        //常规        rv.setAdapter(new Adapter());        LinearLayoutManager m = new LinearLayoutManager(context);        m.setOrientation(LinearLayoutManager.HORIZONTAL);        rv.setLayoutManager(m);        //自动居中        LinearSnapHelper h = new LinearSnapHelper();        h.attachToRecyclerView(rv);        //页边距        rv.addItemDecoration(new GalleryItemDecoration());        //动画        s = new ScrollManager(rv);        //高斯模糊        //初始化高斯模糊图        array = init();        setBlurImage(bg);        rv.addOnScrollListener(new RecyclerView.OnScrollListener() {            @Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                if (newState == RecyclerView.SCROLL_STATE_IDLE) {                    setBlurImage(bg);                }            }        });    }    private SparseArray init() {        SparseArray array = new SparseArray<>();        for (int i = 0; i < 3; i ++) {            int r = res[i];            Bitmap b = BitmapFactory.decodeResource(context.getResources(), r);            Bitmap nb = BlurBitmapUtil.blurBitmap(context, b, 15f);            Drawable nd = new BitmapDrawable(nb);            array.put(i,nd);        }        return array;    }    private Drawable old;    private void setBlurImage(RelativeLayout bg) {        int position = s.getPosition();        Drawable d = array.get(position);        if (d == old) {            return;        }        if (old == null) {            bg.setBackgroundDrawable(d);        } else {            TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[]{old,d});            bg.setBackgroundDrawable(transitionDrawable);            transitionDrawable.startTransition(500);        }        old = d;    }    class Adapter extends RecyclerView.Adapter {        @Override        public CommonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            return new CommonViewHolder(LayoutInflater.from(context).inflate(R.layout.item,parent,false));        }        @Override        public void onBindViewHolder(CommonViewHolder holder, int position) {            ImageView iv = (ImageView) holder.holdAndGetView(R.id.iv);            Glide.with(context).load(res[position]).into(iv);        }        @Override        public int getItemCount() {            return res.length;        }    }}
   
public class GalleryItemDecoration extends RecyclerView.ItemDecoration {    private final String TAG = "GalleryItemDecoration";    public static int mPageMargin = 0;          // 每一个页面默认页边距    public static int mLeftPageVisibleWidth = 50; // 中间页面左右两边的页面可见部分宽度    public static int mItemComusemY = 0;    public static int mItemComusemX = 0;    @Override    public void getItemOffsets(Rect outRect, final View view, final RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        //这个类的方法应该只会被调用k次 是一个专门对item操作的类        final int position = parent.getChildAdapterPosition(view);        final int itemCount = parent.getAdapter().getItemCount();        parent.post(new Runnable() {            @Override            public void run() {                LinearLayoutManager lm = (LinearLayoutManager) parent.getLayoutManager();                if (lm.getOrientation() == LinearLayoutManager.HORIZONTAL) {                    onSetHoritiontalParams(parent, view, position, itemCount);                } else {                    onSetVerticalParams(parent, view, position, itemCount);                }            }        });    }    private void onSetVerticalParams(ViewGroup parent, View itemView, int position, int itemCount) {        int itemNewWidth = parent.getWidth();        int itemNewHeight = parent.getHeight() - dpToPx(4 * mPageMargin + 2 * mLeftPageVisibleWidth);        mItemComusemY = itemNewHeight + dpToPx(2 * mPageMargin);        // 适配第0页和最后一页没有左页面和右页面,让他们保持左边距和右边距和其他项一样        int topMargin = position == 0 ? dpToPx(mLeftPageVisibleWidth + 2 * mPageMargin) : dpToPx(mPageMargin);        int bottomMargin = position == itemCount - 1 ? dpToPx(mLeftPageVisibleWidth + 2 * mPageMargin) : dpToPx(mPageMargin);        setLayoutParams(itemView, 0, topMargin, 0, bottomMargin, itemNewWidth, itemNewHeight);    }    private void onSetHoritiontalParams(ViewGroup parent, View itemView, int position, int itemCount) {        //注意 我们xml中定义了padding,所以才没有贴顶        int itemNewWidth = parent.getWidth() - dpToPx(4 * mPageMargin + 2 * mLeftPageVisibleWidth);        int itemNewHeight = parent.getHeight();        mItemComusemX = itemNewWidth + dpToPx(2 * mPageMargin);//这个引用啥意思 平均单个item整个的宽度        //mPageMargin就是页之间的边距 默认是0 由于有padding 所以没有贴在一起 我觉得设计的非常不合理 但是无伤大雅        int leftMargin = position == 0 ? dpToPx(mLeftPageVisibleWidth + 2 * mPageMargin) : dpToPx(mPageMargin);        int rightMargin = position == itemCount - 1 ? dpToPx(mLeftPageVisibleWidth + 2 * mPageMargin) : dpToPx(mPageMargin);        setLayoutParams(itemView, leftMargin, 0, rightMargin, 0, itemNewWidth, itemNewHeight);    }    private void setLayoutParams(View itemView, int left, int top, int right, int bottom, int itemWidth, int itemHeight) {        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) itemView.getLayoutParams();        boolean mMarginChange = false;        boolean mWidthChange = false;        boolean mHeightChange = false;        if (lp.leftMargin != left || lp.topMargin != top || lp.rightMargin != right || lp.bottomMargin != bottom) {            lp.setMargins(left, top, right, bottom);            mMarginChange = true;        }        if (lp.width != itemWidth) {            lp.width = itemWidth;            mWidthChange = true;        }        if (lp.height != itemHeight) {            lp.height = itemHeight;            mHeightChange = true;        }        // 这里的if考虑到的是缩放动画情况        if (mWidthChange || mMarginChange || mHeightChange) {            itemView.setLayoutParams(lp);        }    }    private static int dpToPx(int dp) {        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);    }}

public class ScrollManager {    private static final String TAG = "ScrollManager";    private RecyclerView mGalleryRecyclerView;    private LinearSnapHelper mLinearySnapHelper;    private PagerSnapHelper mPagerSnapHelper;    private int mPosition = 0;    // 使偏移量为左边距 + 左边Item的可视部分宽度    private int mConsumeX = 0;    private int mConsumeY = 0;    // 滑动方向    private int slideDirct = SLIDE_RIGHT;    private static final int SLIDE_LEFT = 1;    // 左滑    private static final int SLIDE_RIGHT = 2;   // 右滑    private static final int SLIDE_TOP = 3;     // 上滑    private static final int SLIDE_BOTTOM = 4;  // 下滑    public ScrollManager(final RecyclerView mGalleryRecyclerView) {        this.mGalleryRecyclerView = mGalleryRecyclerView;        mGalleryRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {            @Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);                if (!mGalleryRecyclerView.isAttachedToWindow()) {//这里可能有错                    return;                }                LinearLayoutManager lm = (LinearLayoutManager)mGalleryRecyclerView.getLayoutManager();                if (lm.getOrientation() == LinearLayoutManager.HORIZONTAL) {                    onHoritiontalScroll(recyclerView, dx);                } else {                    onVerticalScroll(recyclerView, dy);                }            }        });    }//    public void updateComsume() {//        mConsumeX += dpToPx(GalleryItemDecoration.mLeftPageVisibleWidth + GalleryItemDecoration.mPageMargin * 2);//        mConsumeY += dpToPx(GalleryItemDecoration.mLeftPageVisibleWidth + GalleryItemDecoration.mPageMargin * 2);//    }    /**     * 垂直滑动     *     * @param recyclerView     * @param dy     */    private void onVerticalScroll(final RecyclerView recyclerView, int dy) {        mConsumeY += dy;        if (dy > 0) {            slideDirct = SLIDE_BOTTOM;        } else {            slideDirct = SLIDE_TOP;        }        // 让RecyclerView测绘完成后再调用,避免GalleryAdapterHelper.mItemHeight的值拿不到        recyclerView.post(new Runnable() {            @Override            public void run() {                int shouldConsumeY = GalleryItemDecoration.mItemComusemY;                // 获取当前的位置                int position = getPosition(mConsumeY, shouldConsumeY);                float offset = (float) mConsumeY / (float) shouldConsumeY;     // 位置浮点值(即总消耗距离 / 每一页理论消耗距离 = 一个浮点型的位置值)                // 避免offset值取整时进一,从而影响了percent值                if (offset >= ((LinearLayoutManager)mGalleryRecyclerView.getLayoutManager()).findFirstVisibleItemPosition() + 1 && slideDirct == SLIDE_BOTTOM) {                    return;                }                // 获取当前页移动的百分值                float percent = offset - ((int) offset);                // 设置动画变化                AnimManager.getInstance().setAnimation(recyclerView, position, percent);            }        });    }    /**     * 水平滑动     *     * @param recyclerView     * @param dx     */    private void onHoritiontalScroll(final RecyclerView recyclerView, final int dx) {        mConsumeX += dx;        if (dx > 0) {            // 右滑            slideDirct = SLIDE_RIGHT;        } else {            // 左滑            slideDirct = SLIDE_LEFT;        }        //获取position        // 让RecyclerView测绘完成后再调用,避免GalleryAdapterHelper.mItemWidth的值拿不到        recyclerView.post(new Runnable() {            @Override            public void run() {                int shouldConsumeX = GalleryItemDecoration.mItemComusemX;//获取图片宽+2*padding                int position = getPosition(mConsumeX, shouldConsumeX);                float offset = (float) mConsumeX / (float) shouldConsumeX;     // 位置浮点值(即总消耗距离 / 每一页理论消耗距离 = 一个浮点型的位置值)                // 避免offset值取整时进一,从而影响了percent值                //我觉得是应该避免一下 但是他这个避免方式我看不懂                if (offset >= ((LinearLayoutManager)mGalleryRecyclerView.getLayoutManager()).findFirstVisibleItemPosition() + 1 && slideDirct == SLIDE_RIGHT) {                    return;                }                // 获取当前页移动的百分值 所以这里获取的                float percent = offset - ((int) offset);                // 设置动画变化                AnimManager.getInstance().setAnimation(recyclerView, position, percent);            }        });    }    /**     * 获取位置     *     * @param mConsumeX      实际消耗距离     * @param shouldConsumeX 理论消耗距离     * @return     */    private int getPosition(int mConsumeX, int shouldConsumeX) {        float offset = (float) mConsumeX / (float) shouldConsumeX;        int position = Math.round(offset);        // 四舍五入获取位置        mPosition = position;        return position;    }    public int getPosition() {        return mPosition;    }    private static int dpToPx(int dp) {        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);    }}
   
public class AnimManager {    private static final String TAG = "AnimManager";    private static AnimManager INSTANCE;    public static final int ANIM_BOTTOM_TO_TOP = 0;    public static final int ANIM_TOP_TO_BOTTOM = 1;    private int mAnimType = ANIM_BOTTOM_TO_TOP; //动画类型    private float mAnimFactor = 0.2f;   //变化因子    public static AnimManager getInstance() {        if (INSTANCE == null) {            INSTANCE = new AnimManager();        }        return INSTANCE;    }    public void setAnimation(RecyclerView recyclerView, int position, float percent) {        switch (mAnimType) {            case ANIM_BOTTOM_TO_TOP:                setBottomToTopAnim(recyclerView, position, percent);                break;            case ANIM_TOP_TO_BOTTOM:                setTopToBottomAnim(recyclerView, position, percent);                break;            default:                setBottomToTopAnim(recyclerView, position, percent);                break;        }    }    /**     * 从下到上的动画效果     *     * @param recyclerView     * @param position     * @param percent     */    private void setBottomToTopAnim(RecyclerView recyclerView, int position, float percent) {        View mCurView = recyclerView.getLayoutManager().findViewByPosition(position);       // 中间页        View mRightView = recyclerView.getLayoutManager().findViewByPosition(position + 1); // 左边页        View mLeftView = recyclerView.getLayoutManager().findViewByPosition(position - 1);  // 右边页        if (percent <= 0.5) {            if (mLeftView != null) {                mLeftView.setScaleX((1 - mAnimFactor) + percent * mAnimFactor);                mLeftView.setScaleY((1 - mAnimFactor) + percent * mAnimFactor);            }            if (mCurView != null) {                mCurView.setScaleX(1 - percent * mAnimFactor);                mCurView.setScaleY(1 - percent * mAnimFactor);            }            if (mRightView != null) {                mRightView.setScaleX((1 - mAnimFactor) + percent * mAnimFactor);                mRightView.setScaleY((1 - mAnimFactor) + percent * mAnimFactor);            }        } else {            if (mLeftView != null) {                mLeftView.setScaleX(1 - percent * mAnimFactor);                mLeftView.setScaleY(1 - percent * mAnimFactor);            }            if (mCurView != null) {                mCurView.setScaleX((1 - mAnimFactor) + percent * mAnimFactor);                mCurView.setScaleY((1 - mAnimFactor) + percent * mAnimFactor);            }            if (mRightView != null) {                mRightView.setScaleX(1 - percent * mAnimFactor);                mRightView.setScaleY(1 - percent * mAnimFactor);            }        }    }    /***     * 从上到下的效果     */    private void setTopToBottomAnim(RecyclerView recyclerView, int position, float percent) {        View mCurView = recyclerView.getLayoutManager().findViewByPosition(position);       // 中间页        View mRightView = recyclerView.getLayoutManager().findViewByPosition(position + 1); // 左边页        View mLeftView = recyclerView.getLayoutManager().findViewByPosition(position - 1);  // 右边页        if (percent <= 0.5) {            if (mLeftView != null) {                mLeftView.setScaleX(1 - percent * mAnimFactor);                mLeftView.setScaleY(1 - percent * mAnimFactor);            }            if (mCurView != null) {                mCurView.setScaleX((1 - mAnimFactor) + percent * mAnimFactor);                mCurView.setScaleY((1 - mAnimFactor) + percent * mAnimFactor);            }            if (mRightView != null) {                mRightView.setScaleX(1 - percent * mAnimFactor);                mRightView.setScaleY(1 - percent * mAnimFactor);            }        } else {            if (mLeftView != null) {                mLeftView.setScaleX((1 - mAnimFactor) + percent * mAnimFactor);                mLeftView.setScaleY((1 - mAnimFactor) + percent * mAnimFactor);            }            if (mCurView != null) {                mCurView.setScaleX(1 - percent * mAnimFactor);                mCurView.setScaleY(1 - percent * mAnimFactor);            }            if (mRightView != null) {                mRightView.setScaleX((1 - mAnimFactor) + percent * mAnimFactor);                mRightView.setScaleY((1 - mAnimFactor) + percent * mAnimFactor);            }        }    }    public void setmAnimFactor(float mAnimFactor) {        this.mAnimFactor = mAnimFactor;    }    public void setmAnimType(int mAnimType) {        this.mAnimType = mAnimType;    }}

public class BlurBitmapUtil {    //图片缩放比例    private static final float BITMAP_SCALE = 0.4f;    /**     * 模糊图片的具体方法     *     * @param context 上下文对象     * @param image   需要模糊的图片     * @return 模糊处理后的图片     */    public static Bitmap blurBitmap(Context context, Bitmap image, float blurRadius) {        // 计算图片缩小后的长宽        int width = Math.round(image.getWidth() * BITMAP_SCALE);        int height = Math.round(image.getHeight() * BITMAP_SCALE);        // 将缩小后的图片做为预渲染的图片        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);        // 创建一张渲染后的输出图片        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);        // 创建RenderScript内核对象        RenderScript rs = RenderScript.create(context);        // 创建一个模糊效果的RenderScript的工具对象        ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));        // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间        // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);        // 设置渲染的模糊程度, 25f是最大模糊度        blurScript.setRadius(blurRadius);        // 设置blurScript对象的输入内存        blurScript.setInput(tmpIn);        // 将输出数据保存到输出内存中        blurScript.forEach(tmpOut);        // 将数据填充到Allocation中        tmpOut.copyTo(outputBitmap);        return outputBitmap;    }}


想学习重写LayoutManager的,可以看看鸿洋公众号里的recycler view仿探探

更多相关文章

  1. Android多媒体学习十三:检索MediaStore中的Video和其对应的缩略图
  2. 利用drozer进行Andriod安全测试
  3. android开发之读取xml文件
  4. Android(安卓)Layout之四:Table Layout
  5. android ListView中给Item的每个控件设置单击事件
  6. android中利用GPS获取位置信息的源码分析
  7. @dimen/padding_medium tools:context 都什么意思
  8. Android(安卓)Material Design初步认识
  9. MediaPlayer的使用 带有seekBar

随机推荐

  1. 7.1.5 选项卡结合案例详解
  2. android minui fb显示相关函数
  3. 在Android(安卓)Studio 中 activity的四
  4. Android(安卓)EditText默认不弹出输入法,
  5. Android(安卓)CTS 错误报告提取脚本
  6. Android(安卓)浅析 Broadcast(三) 发送原
  7. android 获取控件大小
  8. 庆祝一下,Android视频采集+H264编码成功
  9. Android编译系统(二)Android架构
  10. Android(安卓)Studio自动化快速实现Parce