zoukankan      html  css  js  c++  java
  • Android画廊效果

    1.概述

      

      最近项目中需要类似上图这种可滚动、点击选中居中的画廊效果,于是萌生了一些想法.最开始想到的这种横向滚动的效果可以用HorizontalScrollView来实现(需要考虑item复用);当然也可以使ViewPager,这需要解决一屏多显和点击事件的问题;再有,就是通过RecyclerView线性横向布局来实现,但是需要处理滚动选中.暂时,就这三种方式了,无一例外,它们都需要选中后居中放大,更甚者,需要添加图片的倒影效果.

    2.ViewPager和RecyclerView实现

    2.1 ViewPager实现方式

      淘来的ViewPager一屏多显图

    原理就一个属性android:clipChildren="false",该属性的意思就是在子View进行绘制时不要去裁切它们的显示范围;在布局文件中

    <RelativeLayout  
            android:layout_width="match_parent" 
            android:layout_height="160dp"
            android:clipChildren="false" 
            android:layout_centerInParent="true" 
            android:background="#aadc71ff" > 
        <android.support.v4.view.ViewPager 
            android:id="@+id/id_viewpager" 
            android:layout_width="match_parent"         
            android:layout_marginLeft="60dp"
            android:layout_marginRight="60dp" 
            android:clipChildren="false" 
            android:layout_height="120dp" 
            android:layout_gravity="center" />
    </RelativeLayout>

    给ViewPager及其控件都设置了android:clipChildren="false"

    ViewPager的宽度是match_parent,左后个设置了60dp的边距,就是为了显示出左右部分的Page.

    在Adapter中

     //设置Page间间距
    mViewPager.setPageMargin(20);

    以及

    //设置缓存的页面数量
     mViewPager.setOffscreenPageLimit(3);

    这样,一屏多显就搞定了;接下来就是设置滚动切换动画了.思路不外乎:写个类集成ViewPager.PageTransformer;重写transformPage方法.上代码:

    public class ScaleAlphaPageTransformer implements ViewPager.PageTransformer{
        public static final float MAX_SCALE = 1.0f;
        public static final float MIN_SCALE = 0.6f;
        public static final float MAX_ALPHA = 1.0f;
        public static final float MIN_ALPHA = 0.5f;
        
        private boolean alpha = true;
        private boolean scale = true;
    
        @Override
        public void transformPage(View page, float position) {
    
            if (position < -1) {
                position = -1;
            } else if (position > 1) {
                position = 1;
            }
    
            float tempScale = position < 0 ? 1 + position : 1 - position;
    
            if(scale){
                float slope = (MAX_SCALE - MIN_SCALE) / 1;
                //一个公式
                float scaleValue = MIN_SCALE + tempScale * slope;
                page.setScaleX(scaleValue);
                page.setScaleY(scaleValue);
            }
            if(alpha){
                //模糊
                float alope = (MAX_ALPHA - MIN_ALPHA) / 1;
                float alphaValue = MIN_ALPHA + tempScale * alope;
                page.setAlpha(alphaValue);
            }
        }
        
        /***
         * 设置是否模糊和改变大小
         * @param alpha
         * @param scale
         */
        public void setType(boolean alpha, boolean scale){
            this.alpha = alpha;
            this.scale = scale;
        }
    }

    于是在Activity中,有

     ScaleAlphaPageTransformer mScaleAlphaPageTransformer = new ScaleAlphaPageTransformer();
            mScaleAlphaPageTransformer.setType(true, true);
            viewPager.setPageTransformer(true, mScaleAlphaPageTransformer);
            viewPager.setCurrentItem(0);
            viewPager.setOnPageChangeListener(new OnPageChangeListener() {
    
                @Override
                public void onPageSelected(int arg0) {
                    Log.e("----------->选中", "" + arg0);
                }
    
                @Override
                public void onPageScrolled(int arg0, float arg1, int arg2) {
                    if (vpLayout != null) {
                        vpLayout.invalidate();
                    }
    
                }
    
                @Override
                public void onPageScrollStateChanged(int arg0) {
                }
            });
    
            vpLayout.setOnTouchListener(new OnTouchListener() {
    
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    v.performClick();
                    return viewPager.dispatchTouchEvent(event);
                }
            });

    这样的话,切换缩放的动画也解决了;

    2.2 RecyclerView实现方式

      淘来的一张图,效果不错,要实现这种效果,需要搞定滑动结束后某个图片居中和滚动缩放;分两步走,

      ①滑动结束后停留在某张图片居中

      Support RecyclerView 24.2.0中增加一个非常重要的类SnapHelper,他的作用是让RecyclerView滑动视图后使停止位置正好停在某页的正中间。使用方式很简单
    重点在于new LinearSnapHelper().attachToRecyclerView(recyclerView);

    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
    recyclerView.setLayoutManager(linearLayoutManager);
    new LinearSnapHelper().attachToRecyclerView(recyclerView);

      这样就解决了第一个问题.

      ②滑动缩放

      不难看出,RecyclerView的滑动缩放必须要监听RecyclerView的滑动;

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            // dx>0则表示右滑, dx<0表示左滑, dy<0表示上滑, dy>0表示下滑
            mCurrentItemOffset += dx;
            computeCurrentItemPos();
            onScrolledChangedCallback();
        }
    });

    mCurrentItemOffset为滑动总距离,Card每页滑动的距离是固定的,根据这个可以计算出当前显示的位置。缩放看onScrolledChangedCallback这个函数,有了滑动位置就能实时计算滑动某页的百分比
    float percent = (float) Math.max(Math.abs(offset) * 1.0 / mOnePageWidth, 0.0001);

    得到百分比, 再获取当前位置相邻的视图调用setScaleY函数实现缩放

    /**
     * RecyclerView位移事件监听, view大小随位移事件变化
     */
    private void onScrolledChangedCallback() {
        int offset = mCurrentItemOffset - mCurrentItemPos * mOnePageWidth;
        float percent = (float) Math.max(Math.abs(offset) * 1.0 / mOnePageWidth, 0.0001);
    
        View leftView = null;
        View currentView;
        View rightView = null;
        if (mCurrentItemPos > 0) {
            leftView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos - 1);
        }
        currentView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos);
        if (mCurrentItemPos < mRecyclerView.getAdapter().getItemCount() - 1) {
            rightView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos + 1);
        }
    
        if (leftView != null) {
            // y = (1 - mScale)x + mScale
            leftView.setScaleY((1 - mScale) * percent + mScale);
        }
        if (currentView != null) {
            // y = (mScale - 1)x + 1
            currentView.setScaleY((mScale - 1) * percent + 1);
        }
        if (rightView != null) {
            // y = (1 - mScale)x + mScale
            rightView.setScaleY((1 - mScale) * percent + mScale);
        }
    }//这样缩放也搞定了.

    3.小结  

      目前,个人比较倾向于第二种方式,item复用问题RecyclerView已经帮我们解决了,而且图片的网络加载是一个耗时的操作,利用RecyclerView可以很方便的完成,而ViewPager的方式点击事件是不好实现的,尤其在一屏多显的情景下,item条目复用也会有问题.实际使用可能还会有一些问题,先写到这,后面发现了的话,再来补充.


  • 相关阅读:
    Nginx之常用操作
    linux之信息查看
    KPI VS OKR
    python之jupyter安装与使用
    python进阶资源
    python之排序(sort/sorted)
    python之文件操作
    远程连接工具
    docker之本地连接
    Windows服务器连接
  • 原文地址:https://www.cnblogs.com/fuyaozhishang/p/6794627.html
Copyright © 2011-2022 走看看