技术这东西就是需要日积月累的,每天学习一点点新的东西,同时复习一下旧的东西,只有这样,坚持一段时间,你的能力才有可能提高,它不是你到用时再去查,而是平时多注意发现新的东西去研究,发现研究过的东西去复习。今天复习一个小知识点,就是用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这么个东西就行了,然后根据自己不同的需求去实现不同的动画就可以了。点击下载源码。