zoukankan      html  css  js  c++  java
  • 一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

    ViewPager的基本用法不必多说,这都很简单,我们可以在ViewPager中加载一个ImageView,也可以加载一个Fragment,这都是目前非常常见的用法。那么我今天说的是ViewPager中的PageTransformer属性,用好这个属性可以让我们的应用更加出彩,OK,那我们就开始吧!

    本文将从如下几方面来介绍:


    1.clipChildren属性
    2.一个页面显示多个ViewPager的Item
    3.初识PagerTransformer
    4.进一步了解PagerTransformer
    5.ViewPager结合CardView


    1.clipChildren属性

    clipChildren属性表示是否限制子控件在该容器所在的范围内,clipChildren属性配合layout_gravity属性,可以用来设置多余部分的显示位置,我这里举一个简单的例子,比如喜马拉雅FM这个应用的首页:

    大家注意看这个应用底部导航栏中中间一个是要比另外四个高的,这种效果很多人就会想到使用一个RelativeLayout布局来实现,其实不用那么麻烦,这种效果一个clipChildren属性就能实现,示例Demo如下:

    代码:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false"
        tools:context="org.lenve.clipchildren.MainActivity">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:layout_alignParentBottom="true"
            android:background="#03b9fc"
            android:orientation="horizontal">
    
            <ImageView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@mipmap/ic_launcher"/>
    
            <ImageView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@mipmap/ic_launcher"/>
    
            <ImageView
                android:layout_width="0dp"
                android:layout_height="72dp"
                android:layout_gravity="bottom"
                android:layout_weight="1"
                android:src="@mipmap/ic_launcher"/>
    
            <ImageView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@mipmap/ic_launcher"/>
    
            <ImageView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@mipmap/ic_launcher"/>
        </LinearLayout>
    </RelativeLayout>
    

    大家看只需要在根节点添加clipChildren属性,然后在第三个ImageView上添加layout_gravity属性即可,layout_gravity属性值为bottom表示控件大小超出后控件底部对齐。效果如下:

    OK,上面是对clipChildren属性一个简单介绍,算是一个铺垫,接下来我们来看看ViewPager。

    2.一个页面显示多个ViewPager的Item

    我们要来解决的第一个问题是如何在一个页面上显示ViewPager的多个item,一共有两种解决方案,第一种就是我们上文所说的clipChildren属性,第二种是clipToPadding属性,我们先来看看使用第一种属性设置的ViewPager:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false"
        tools:context="org.lenve.myviewpagercards.MainActivity">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:layout_marginLeft="60dp"
            android:layout_marginRight="60dp"
            android:clipChildren="false"></android.support.v4.view.ViewPager>
    </RelativeLayout>

    只需要在父容器和ViewPager中都添加上clipChildren属性,然后给ViewPager设置左右两个margin,使其不致于把整个屏幕占满,就是这么简单,我们再来看看ViewPager的Adapter:

    public class MyVpAdater extends PagerAdapter {
        private List<Integer> list;
        private Context context;
    
        public MyVpAdater(Context context, List<Integer> list) {
            this.context = context;
            this.list = list;
        }
    
        @Override
        public int getCount() {
            return list.size();
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView iv = new ImageView(context);
            iv.setImageResource(list.get(position));
            container.addView(iv);
            return iv;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }

    最后再来看看Activity中的代码:

    ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
            viewPager.setPageMargin(80);
            viewPager.setOffscreenPageLimit(3);
            List<Integer> list = new ArrayList<>();
            list.add(R.drawable.p001);
            list.add(R.drawable.p002);
            list.add(R.drawable.p003);
            list.add(R.drawable.p004);
            list.add(R.drawable.p005);
            MyVpAdater adater = new MyVpAdater(this, list);
            viewPager.setAdapter(adater);

    比我们一般使用ViewPager多了两行代码,一个是setOffscreenPageLimit,这个是设置预加载的页数,我们知道默认情况下这个参数为1,也就是左右各预加载一页,但是我们这里要让左右各预加载两页,原因一会再说,另外一个PageMargin就好说了,就是设置ViewPager中两页之间的距离。OK,那我们来看看显示效果:

    OK,就是这么简单,这样,我们现在已经可以在一个页面上来显示多个ViewPager中的item,接下来我们先来看看PageTransformer的简单使用。

    3.初识PagerTransformer

    我们知道可以给ViewPager设置一个setPagerTransformer属性,设置时候需要我们自己来实现PagerTransformer接口,实现这个接口的时候要实现该接口中的方法,transformPage,该方法接收两个参数,其中一个是position,如果你直接打印position出来可能会看得你云里雾里,实际上position表示的是第一个参数View的position,把这两个参数一起打印出来就可以找到规律了:

    比如从第1页滑动到第2页:

    第一页position的变化为  [0,-1]

    第二页position的变化为  [1,0]

    知道了这个我们就可以写一个简单的切换动画了,我希望页面上正中间的item是正常的,两边的item都有一点透明度。那我们可以使用如下方式来定义:

    public class AlphaTransformer implements ViewPager.PageTransformer {
        private float MINALPHA = 0.5f;
    
        /**
         * position取值特点:
         * 假设页面从0~1,则:
         * 第一个页面position变化为[0,-1]
         * 第二个页面position变化为[1,0]
         *
         * @param page
         * @param position
         */
        @Override
        public void transformPage(View page, float position) {
            if (position < -1 || position > 1) {
                page.setAlpha(MINALPHA);
            } else {
                //不透明->半透明
                if (position < 0) {//[0,-1]
                    page.setAlpha(MINALPHA + (1 + position) * (1 - MINALPHA));
                } else {//[1,0]
                    //半透明->不透明
                    page.setAlpha(MINALPHA + (1 - position) * (1 - MINALPHA));
                }
            }
        }
    }

    定义好了之后再设置给ViewPager即可:

    viewPager.setPageTransformer(false, new AlphaTransformer());

    我们再来看看运行效果:

    OK,透明度的效果已经有了。很简单吧!

    4.进一步了解PagerTransformer

    上面是一个简答的效果,遵循这个思路,我们可以做出更多的效果,比如下面这个效果:

    这是一个非常常见的效果,实现思路和前文一致,就是让ImageView动态缩放。那我们来看看这里的PagerTransformer:

    public class ScaleTransformer implements ViewPager.PageTransformer {
        private static final float MIN_SCALE = 0.70f;
        private static final float MIN_ALPHA = 0.5f;
    
        @Override
        public void transformPage(View page, float position) {
            if (position < -1 || position > 1) {
                page.setAlpha(MIN_ALPHA);
                page.setScaleX(MIN_SCALE);
                page.setScaleY(MIN_SCALE);
            } else if (position <= 1) { // [-1,1]
                float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
                if (position < 0) {
                    float scaleX = 1 + 0.3f * position;
                    Log.d("google_lenve_fb", "transformPage: scaleX:" + scaleX);
                    page.setScaleX(scaleX);
                    page.setScaleY(scaleX);
                } else {
                    float scaleX = 1 - 0.3f * position;
                    page.setScaleX(scaleX);
                    page.setScaleY(scaleX);
                }
                page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
            }
        }
    }

    然后给ViewPager设置相应的PagerTransformer:

    viewPager.setPageTransformer(false, new ScaleTransformer());

    就是这么简单。其它复杂的旋转平移等都是按照这个思路来实现,这里不再赘述。

    5.ViewPager结合CardView

    如果你还不会使用CardView,可以参考我之前的文章Android5.0之CardView的使用,那今天我们来看看ViewPager结合CardView会产生怎样的效果呢?


    那么在这之前,我想先介绍一个属性,那就是clipToPadding,这个属性是什么意思呢?它表示是否允许ViewGroup在ViewGroup的padding中进行绘制,默认情况下该属性的值为true,即不允许在ViewGroup的padding中进行绘制。那如果我设置了false呢?我们来看看:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="org.lenve.myviewpagercards2.MainActivity">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:clipToPadding="false"
            android:paddingBottom="24dp"
            android:paddingLeft="48dp"
            android:paddingRight="48dp"
            android:paddingTop="24dp"></android.support.v4.view.ViewPager>
    </RelativeLayout>

    ViewPager的Adapter如下:

    public class MyAdapter extends PagerAdapter {
        private List<Integer> list;
        private Context context;
    
        public MyAdapter(Context context, List<Integer> list) {
            this.context = context;
            this.list = list;
        }
    
        @Override
        public int getCount() {
            return list.size();
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView iv = new ImageView(context);
            iv.setImageResource(list.get(position));
            container.addView(iv);
            return iv;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }

    Activity中的代码:

            ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
            List<Integer> list = new ArrayList<>();
            list.add(R.drawable.p001);
            list.add(R.drawable.p002);
            list.add(R.drawable.p003);
            list.add(R.drawable.p004);
            list.add(R.drawable.p005);
            MyAdapter adapter = new MyAdapter(this, list);
            viewPager.setAdapter(adapter);
            viewPager.setPageMargin(20);

    显示效果如下:

    OK,那这个clipToPadding属性是我们在一个页面中显示多个ViewPager  item的第二种方式。这个CardView式的ViewPager我们就使用这种方式来实现。先来看看效果图:

    整体思路和上文其实是一致的,我们来看看activity的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="org.lenve.myviewpagercards2.MainActivity">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:clipToPadding="false"
            android:paddingBottom="24dp"
            android:paddingLeft="80dp"
            android:paddingRight="80dp"
            android:paddingTop="24dp"></android.support.v4.view.ViewPager>
    </RelativeLayout>

    ViewPager中每一个item的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.CardView android:id="@+id/cardview"
                                        xmlns:android="http://schemas.android.com/apk/res/android"
                                        xmlns:app="http://schemas.android.com/apk/res-auto"
                                        android:layout_width="match_parent"
                                        android:layout_height="wrap_content"
                                        android:orientation="vertical"
                                        app:cardCornerRadius="10dp">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="300dp">
    
            <TextView
                android:id="@+id/tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:gravity="center"
                android:text="我是一个TextView"/>
    
            <Button
                android:layout_width="96dp"
                android:layout_height="36dp"
                android:textColor="#ffffff"
                android:layout_below="@id/tv"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="12dp"
                android:background="@color/colorAccent"
                android:text="我是一个按钮"/>
        </RelativeLayout>
    </android.support.v7.widget.CardView>

    Adapter:

    public class MyAdapter extends PagerAdapter {
        private List<Integer> list;
        private Context context;
        private LayoutInflater inflater;
    
        public MyAdapter(Context context, List<Integer> list) {
            this.context = context;
            this.list = list;
            inflater = LayoutInflater.from(context);
        }
        @Override
        public int getCount() {
            return list.size();
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = inflater.inflate(R.layout.vp_item, container, false);
            container.addView(view);
            return view;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }

    Activity中的代码:

    ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
            List<Integer> list = new ArrayList<>();
            list.add(R.drawable.p001);
            list.add(R.drawable.p002);
            list.add(R.drawable.p003);
            list.add(R.drawable.p004);
            list.add(R.drawable.p005);
            MyAdapter adapter = new MyAdapter(this, list);
            viewPager.setAdapter(adapter);
            viewPager.setPageMargin((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                    48, getResources().getDisplayMetrics()));
            viewPager.setPageTransformer(false, new ScaleTransformer(this));

    最后再来看看我们定义的PageTransformer:

    public class ScaleTransformer implements ViewPager.PageTransformer {
        private Context context;
        private float elevation;
    
        public ScaleTransformer(Context context) {
            this.context = context;
            elevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                    20, context.getResources().getDisplayMetrics());
        }
    
        @Override
        public void transformPage(View page, float position) {
            if (position < -1 || position > 1) {
    
            } else {
                if (position < 0) {
                    ((CardView) page).setCardElevation((1 + position) * elevation);
                } else {
                    ((CardView) page).setCardElevation((1 - position) * elevation);
                }
            }
        }
    }

    很简单,我只是对CardView的阴影做了处理 ,其他属性都没改,这样就有了我们刚才看到的效果。



    Demo下载:http://download.csdn.net/detail/u012702547/9615195


    参考资料:

    http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1030/1870.html


    以上。




  • 相关阅读:
    LOJ 6089 小Y的背包计数问题 —— 前缀和优化DP
    洛谷 P1969 积木大赛 —— 水题
    洛谷 P1965 转圈游戏 —— 快速幂
    洛谷 P1970 花匠 —— DP
    洛谷 P1966 火柴排队 —— 思路
    51Nod 1450 闯关游戏 —— 期望DP
    洛谷 P2312 & bzoj 3751 解方程 —— 取模
    洛谷 P1351 联合权值 —— 树形DP
    NOIP2007 树网的核
    平面最近点对(加强版)
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461671.html
Copyright © 2011-2022 走看看