卡片式Viewpager

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这个应用的首页:


image.png

大家注意看这个应用底部导航栏中中间一个是要比另外四个高的,这种效果很多人就会想到使用一个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表示控件大小超出后控件底部对齐。效果如下:


image.png

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,那我们来看看显示效果:


image.png

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());  

我们再来看看运行效果:


image.png

4.进一步了解PagerTransformer

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

image.png

这是一个非常常见的效果,实现思路和前文一致,就是让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);  

显示效果如下:


image.png

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


image.png

整体思路和上文其实是一致的,我们来看看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);  
            }  
        }  
    }  
}

原文链接
http://blog.csdn.net/u012702547/article/details/52334161

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容