ViewPager+Fragment+PageTransformer实现3D、视差等多种动画效果(雷惊风)

   技术这东西就是需要日积月累的,每天学习一点点新的东西,同时复习一下旧的东西,只有这样,坚持一段时间,你的能力才有可能提高,它不是你到用时再去查,而是平时多注意发现新的东西去研究,发现研究过的东西去复习。今天复习一个小知识点,就是用ViewPager+Fragment+PageTransformer实现滑动动画,很简单,最后我会将源码demo下载地址附上,高手略过啊。

首先我们来看一下第一个效果:


看完效果我们开始做前期的准备工作,我们先通过ViewPager+Fragment实现最普通的滑动效果,我找了三张大图片用来做三个Fragment的背景图,创建我们的每一fragment对应加载的XML布局文件,代码如下:

layout_fragment1

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/rlayout">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/timg1" />
</RelativeLayout>

Layout_fragment2:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:id="@+id/rlayout"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/timg2" />
</RelativeLayout>

Layout_fragment3:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/rlayout"
    android:orientation="vertical">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/timg3" />
</RelativeLayout>

很简单,每个里边一个ImageView,主Activity布局文件里添加一个ViewPager,布局就不贴了,看一下主Activity里边的代码:

public class MainActivity extends AppCompatActivity {
private ViewPager myViewpager;
    private int[] layouts_fragment=new int[]{R.layout.layout_fragment1,R.layout.layout_fragment2,R.layout.layout_fragment3};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myViewpager= (ViewPager) findViewById(R.id.myViewpager);
        myViewpager.setAdapter(new MyPagerAdpter(getSupportFragmentManager()));

    }

    public  class MyPagerAdpter extends FragmentPagerAdapter{

        public MyPagerAdpter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            MyImageViewFragment myfragment= new MyImageViewFragment();
            Bundle bundle= new Bundle();
            bundle.putInt("position",layouts_fragment[position]);
            myfragment.setArguments(bundle);
            return myfragment;
        }

        @Override
        public int getCount() {
            return 3;
        }
    }
}

也很简单,用一个数组保存不同Fragment布局文件id,继承FragmentPagerAdapter自定义一个adpter,在getItem()创建我们的Fragment,通过不同position传递不同layout到Fragment中展示不同的布局,在getCount()方法中返回数量3,在看一下Fragment中代码:

public class MyImageViewFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(getArguments().getInt("position"), null);
    }
}

也很简单,就是根据传递进来的布局id创建Fragment,这样就实现了最普通的滑动效果,上边都是铺垫,后边才是重点,要给ViewPager实现动画效果其实也很简单,google已经给我们提供了相关的类,供我们自定义动画,就是ViewPager.PageTransformer,我们实现ViewPager.PageTransformer接口自定义动画,重写transformPage(View page,float position)方法,里边两个参数,第一个参数表示ViewPage中的每一个Page,第二个参数表示当前Page对应的在屏幕中的位置,如果当前Page正在屏幕中显示那么它对应的position为0,它的前一个Page的position为-1,它的后一个Page的position为1,在滑动过程中会变化,比如我们现在向右滑动当前的这个Page,那么它上一个Page就会漏出来,本身就会慢慢的被滑到屏幕外(右侧),这个过程因为上一个Page在滑动前position为-1,会随着我们手指的滑动慢慢变成0,本身是float类型的,如-1...-0.9861111...-0.837037...-0.5638889...-0.22314 815...0.0,而我们之前在屏幕上显示Page的position便会从0逐渐的变化到1。跟上边是一样的,其他Page都是一样的,向左滑动屏幕,右侧的Page会出来,position都是减小的。向右侧滑动屏幕,左侧的Page便会漏出来,position都是变大的,所以我们现在就根据这个来定义我们的动画,因为我们只需要给当前显示的Page及滑动过程中会显示的Page设置动画就可以了,其他的都不用管,因为用户根本看不到嘛,所以我们要实现上边的效果只需要像下边这样编码就行:

public class MyTransformer implements ViewPager.PageTransformer {
    /**
     * 实现动画主要方法,每一个Fragment在滑动过程中都会调用这个方法,。
     *
     * @param page:每一个Page;
     * @param position:当前Page所在位置,0时表示当前Page正在显示。
     */
    @Override
    public void transformPage(View page, float position) {
        System.out.println("Log_LYL:position_"+position);
        if (position > -1 && position < 1) {
//            效果1:相对于XY轴缩放;
            page.setScaleX(1-Math.abs(position));
            page.setScaleY(1-Math.abs(position));

        }
    }
}

   分析一下那个效果,因为我们只关心显示的和将要显示的Page,所以这里我们只取position-1到1之间的page来做操作,看图中的效果只是一个相对于X,Y轴的缩放效果,向左滑动,右边的page将会显示出来,当前的page将会被推到右侧,分析一下将要漏出的page,他有一个放大的效果,他的position是从-1到0的,我们取绝对值也就是从1-0,所以我们需要让1减去这个值就会满足从0-1的一个过程,也就是从小到大的一个过程。

下边看一下第二个效果:


理解了第一个效果这个效果就好实现了,就是多了一个限制,小到一定程度就停止变小了,代码如下:

page.setScaleX(1-Math.abs(position)<0.9f?0.9f:1-Math.abs(position));
page.setScaleY(1-Math.abs(position)<0.9f?0.9f:1-Math.abs(position));

这个没什么好说的,再看下一个效果:


这是一个3D旋转的效果,看一下代码实现:

page.setPivotX(position < 0f ? page.getWidth() :0f);
page.setPivotY(page.getHeight()*0.5f);
page.setRotationY(position * 45f);

首先我们设置了旋转的轴,然后只旋转45度。再看下一个效果:


这里实现了一个视差效果,看那个苹果就能看出来,我找了几个小图片放到了我们每一个fragment布局文件中,当我们向一个方向滑动ViewPager时,上边的小图片的滑动速度与整体滑动速度并不同步,这是怎么实现的呢,看一下代码:

ViewGroup vg = (ViewGroup) page.findViewById(R.id.rlayout);
for (int i = 0; i < vg.getChildCount(); i++) {
    if (i == 0)
        continue;
    View v = vg.getChildAt(i);
    float factor = (float) Math.random() * 3;
    if (v.getTag() == null) {
        v.setTag(factor);
    } else {
        factor = (float) v.getTag();
    }
    /**每一个子控件达到不同的视差效果,translationX是不一样的
     * position : 0 ~ -1
     * translationX: 0 ~ childView.getWidth();
     */
    v.setTranslationX(factor * v.getWidth() * position);
}

其实就是根据一个随机值来移动每一个子View,当然我们整体的背景图片是不移动的,然后对每一个图片的随机值进行保存,每一个小图标只对应一个随机值,根据这个随机值再加上position的变化来移动图片的位置,是不是感觉很简单很贱。

就说到这里把,其实没什么,最重要的就是知道有ViewPager.PageTransformer这么个东西就行了,然后根据自己不同的需求去实现不同的动画就可以了。点击下载源码

猜你喜欢

转载自blog.csdn.net/liuyonglei1314/article/details/73648477