您的位置:首页 > 其它

ViewPager切换动画及性能优化

2015-06-04 14:49 441 查看
首先我们先展示一个Viewpager的一个Demo

1. 布局文件的编写
<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:background="#000000"
     >
    <android.support.v4.view.ViewPager 
        android:id="@+id/id_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</RelativeLayout>


2. Mainactivity的编写
public class MainActivity extends Activity {
	private ViewPager viewPager;
	private MyAdapter pagerAdapter ;
	private int[] mImgIds = new int[]{R.drawable.one,R.drawable.two,R.drawable.three};
	private Context mcontext;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		mcontext = MainActivity.this;
		initView();
	}
	private void initView() {
		// TODO Auto-generated method stub
		viewPager = (ViewPager) findViewById(R.id.id_viewpager);
		pagerAdapter = new MyAdapter(mcontext, mImgIds);
		viewPager.setAdapter(pagerAdapter);	
	}
}


3. 适配器编写。

public class MyAdapter extends PagerAdapter{
	private int[] mImgIds;
	private Context mcontext;
	
	
	public MyAdapter(Context mcontext, int[] mImgIds) {
		super();
		this.mImgIds = mImgIds;
		this.mcontext = mcontext;
	}

	@Override
	public void destroyItem(ViewGroup container, int position, Object object) {
		// TODO Auto-generated method stub
		 container.removeView((View) object);  
	}

	@Override
	public Object instantiateItem(ViewGroup container, int position) {
		// TODO Auto-generated method stub
		ImageView imageView = new ImageView(mcontext);
		imageView.setImageResource(mImgIds[position]);
		imageView.setScaleType(ScaleType.CENTER_INSIDE);  
		container.addView(imageView);  
		return imageView;  
	}

	@Override
	public boolean isViewFromObject(View arg0, Object arg1) {
		// TODO Auto-generated method stub
		return arg0 == arg1;
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mImgIds.length;  
	}
}


好的,现在这个代码已经写完了。viewpager里面分别加入了3张图片,切换子view的时候是没有动画效果的。

那么问题来了,如果我们要加入动画,应该需要什么?

1. 因为动画效果是根据我们手势操作来动的,所以我们要监听用户的手势。那么viewpager提供这样的方法呢?有的,就是一个叫做发现了一个叫做
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)的方法

仔细研究下这几个参数
position 表示 当前viewpager处于第几页,positionOffset 就是表示这个pager的偏移的值,这个值是跟随我们的手势不断变化的

从第0页切换到第1页,就是向左边滑动的时候,我们打印一下这个参数看下变化



说白了,
就是像右边滑动,positionOffset的变化区间是【0,1】

同样的,我们页打印一下像左边滑动的信息



像左边滑动,positionOffset的变化区间是【1,0】

可是有个问题。在onPageScrolled中我们每次只能拿到一个view的偏移量啊,我们要对2个子view进行动画,必须拿到2个动态变化的偏移量才行

其实android已经提供给我们这个方法了,只需要ViewPager.PageTransformer 这个接口就可以了。里面会提供给我们一个
void transformPage(View view, float position) 方法,这个方法中可以同时获取左右2个变化的子view的偏移量的结果
但是这里偏移量有点不同,举个例子
当我们滑动时:会打印出当然ViewPager中存活的每个View以及它们的position的变化

* 比如从第0页滑动到第1页时候,

* 第0页的positon :
【0,-1】

* 第1页的positon : 【-1,0】

豁然发现,这个positon非常适合做渐变,缩放等动画效果的控制参数

接下来我们就在void transformPage(View arg0, float arg1) 里面,根据positon的变化区域,为我们的左右2个子view做动画



因为要实现旋转的动画效果,

1. 所以必须给这个旋转动画设置一个梯度,就是一个变化区间,让他能从0度,根据我们的手势,变化到另一个角度
2.必须给这个旋转动画设置一个中定点

这个梯度,我们借助positon来实现就可以了,给他整个数学公司,让他也随着position的变化而变化
float mRot = (ROT_MAX * position);

左边那一页的posiotn是从【0,-1】,那么左边那一页的旋转角度应该是从【0,-20度】

右边那一页的positon是从【1,0】,那么右边那一页的旋转角度应该是从【20,0】

上源代码把

public class pagerAnimation  implements ViewPager.PageTransformer  {
<span style="white-space:pre">	</span>//动画梯度
<span style="white-space:pre">	</span>private float ROT_MAX = 50;
<span style="white-space:pre">	</span>private float mRot ;
<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public void transformPage(View view, float position) {
<span style="white-space:pre">		</span>// TODO Auto-generated method stub
<span style="white-space:pre">		</span> //这个是左边页的动画 
        if (position < 0)  
        {  
        <span style="white-space:pre">	</span>//现在我们要根据这个position来定义我们的每个view的角度变化的梯度
            mRot = (ROT_MAX * position);  //posiotn是从【0,-1】,所以mRot是从【0,-20度】
            //旋转的中心点是哪里?我们把他定义在正下方中间处
            view.setPivotX(view.getMeasuredWidth() * 0.5f);  
            view.setPivotY(view.getMeasuredHeight());  
            view.setRotation(mRot);  
        } 
       //这个是右边页的动画
        else  if (position > 0) 
        {  
            mRot = (ROT_MAX * position);  //posiotn是从【1,0】,所以mRot是从【20度到0度】
            view.setPivotX(view.getMeasuredWidth() * 0.5f);  
            view.setPivotY(view.getMeasuredHeight());  
            view.setRotation(mRot);  
        }  
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>
}


好的,这样我们的动画就写好了。
别忘了我们还是回到viewpager中,给他设置一下我们定义的这个切换动画

private void initView() {
		// TODO Auto-generated method stub
		viewPager = (ViewPager) findViewById(R.id.id_viewpager);
		pagerAdapter = new MyAdapter(mcontext, mImgIds);
		viewPager.setAdapter(pagerAdapter);	
		viewPager.setPageTransformer(true, new pagerAnimation());
	}


具体效果,请参考我们的平板

关于Viewpager的性能优化

如果我们的viewpager中加入了多个view,而且这多个view的布局都非常的深,加载非常多的高清图片,那么我们就会发现,viewpager在切换的时候非常的卡,加上动画就跟卡了,我们可以开启Viewpager的缓存功能来解决他,并且让他加载第0页的pager的同时,就去预加载其他页

<android.support.v4.view.ViewPager 
        android:id="@+id/id_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:persistentDrawingCache="all"
        />


这里viewpager就会去缓存我们的动画和图片,不再重复的加载(注意,adapter的ondestoryitem方法也要修改,不要再让他销毁之前加载的内容)

代码中我们去开启预加载

private void initView() {
		// TODO Auto-generated method stub
		viewPager = (ViewPager) findViewById(R.id.id_viewpager);
		pagerAdapter = new MyAdapter(mcontext, mImgIds);
		viewPager.setOffscreenPageLimit(3);
		viewPager.setAdapter(pagerAdapter);	
		viewPager.setPageTransformer(true, new pagerAnimation());
	}


这样加载第0页,就回去预加载另外的2页

这些都是牺牲内存去换取时间的方法,并不好。

最根本的还是要回头解决子view布局过深和加载过多高清大图的问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: