在上一篇文章(TabLayout與ViewPager配合使用踩坑總結)中我記錄了TabLayout搭配ViewPager使用過程中的踩坑過程,那麼這一篇文章我來寫一下ViewPager切換的視差動畫效果及背景漸變過渡是如何實現的!
一、視差動畫實現
慣例首先來看看ViewPager的切換效果:
注意下方的三行文字,在切換的時候是有一個視覺差的,也就是它們仨不是以同一個偏移量移動,可以看到名稱那一行在滑動時偏移量比其他的大,第二行比第三行偏移量大,這就是我們說的視差效果,那麼如何實現呢?
在上一篇的工程源碼中可以看到,在PagerAdapter的實現中,instantiateItem方法最後我用一個數組mLayoutViewIdsMap將當前item佈局中所有的id數組記錄下來了:
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View view = LayoutInflater.from(MainActivity.this)
.inflate(R.layout.viewpager_item, null, false);
GirlBean bean = girlList.get(position);
if (null == bean) {
return null;
}
TextView tvName = view.findViewById(R.id.tv_name);
tvName.setText(bean.name);
TextView tvDesc = view.findViewById(R.id.tv_desc);
tvDesc.setText(bean.desc);
TextView tvLike = view.findViewById(R.id.tv_like);
tvLike.setText(bean.like);
//存儲佈局ID
int[] ids = new int[] {
R.id.tv_name, R.id.tv_desc, R.id.tv_like
};
mLayoutViewIdsMap.put(position, ids);
container.addView(view);
return view;
}
接下來就是使用ViewPager的setPageTransformer方法,這個方法可以給ViewPager設置切換場景的動畫效果,我們這裏只列出這個項目中用到的,就是每個Item中各個控件的偏移視差效果動畫。
新建一個類實現PageTransformer:
private class ParallaxTransformer implements ViewPager.PageTransformer {
float parallaxCoefficient;
float distanceCoefficient;
public ParallaxTransformer(float parallaxCoefficient, float distanceCoefficient) {
this.parallaxCoefficient = parallaxCoefficient;
this.distanceCoefficient = distanceCoefficient;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void transformPage(View page, float position) {
float scrollXOffset = page.getWidth() * parallaxCoefficient;
ViewGroup pageViewWrapper = (ViewGroup) page;
@SuppressWarnings("SuspiciousMethodCalls")
int[] layer = mLayoutViewIdsMap.get(viewPager.getCurrentItem());
for (int id : layer) {
View view = page.findViewById(id);
if (view != null) {
view.setTranslationX(scrollXOffset * position);
}
scrollXOffset *= distanceCoefficient;
}
}
}
transformPage方法中兩個參數,page表示當前滑動的ViewPager中的Item,position表示滑動的位置,比如0->-1,1->0,具體的可以打log觀察。
這裏我們主要是取出每個position對應的Item的各個控件,然後對它設置一個setTranslationX偏移量,因爲它們自身在佈局中的位置不一樣,所以這裏通過view.setTranslationX(scrollXOffset * position)運行的效果也不一樣,所以這樣就實現了我們說的視差效果,如果有需要我們還可以對控件設置透明度等等。
最後調用
viewPager.setPageTransformer(true,
new ParallaxTransformer(PARALLAX_COEFFICIENT, DISTANCE_COEFFICIENT));
設置給ViewPager即可。
二、背景圖片切換過渡
可以看出在切換過程中,背景圖片是有一個漸變的效果的,這個背景位置因爲是靜態的,所以不能跟隨ViewPager一起左右切換,所以圖片就不適合放到PagerAdapter的Item佈局中,應該放到ViewPager平級的佈局文件中,作爲一個底圖背景:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="match_parent">
<ImageView
android:id="@+id/bg1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="@drawable/girl1" />
<ImageView
android:id="@+id/bg2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="@drawable/girl2" />
<ImageView
android:id="@+id/bg3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="@drawable/girl3" />
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.zhangyan.mytablayout.tablayout.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
app:tabGravity="fill"
app:tabIndicatorColor="#CBA788"
app:tabIndicatorHeight="3dp"
app:tabLineOffset="10dp"
app:tabMode="fixed"
app:tabSelectedTextColor="#CBA788"
app:tabTextColor="#CCFFFFFF" />
</RelativeLayout>
這裏我放了三個ImageView作爲背景。
bgImg1 = findViewById(R.id.bg1);
bgImg2 = findViewById(R.id.bg2);
bgImg3 = findViewById(R.id.bg3);
//剛進來只顯示第一張背景
bgImg2.getBackground().setAlpha(0);
bgImg3.getBackground().setAlpha(0);
初始化的時候先將後兩張透明度設爲0,這樣只顯示出第一張。
剩下的處理邏輯就需要依賴OnPageChangeListener中實現了,實現OnPageChangeListener這個類:
private ViewPager.OnPageChangeListener mOnPageChangeListener =
new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
float fraction = positionOffset;
if (position == 0) {
bgImg1.getBackground().setAlpha(255);
bgImg2.getBackground().setAlpha((int) (fraction * 255));
bgImg3.getBackground().setAlpha(0);
}
if (position == 1) {
bgImg2.getBackground().setAlpha(255);
bgImg3.getBackground().setAlpha((int) (fraction * 255));
bgImg1.getBackground().setAlpha(0);
}
if (position == 2) {
bgImg3.getBackground().setAlpha(255);
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
};
在onPageScrolled這個方法中有三個參數:
- position:當前滑動pager的position,第一張到第二張position從0開始,完全滑動到第二張時,position=1;第二張到第三張position從1開始,完全滑動到第三張時,position=2;以此類推。
- positionOffset:滑動的比例,往下一張滑動時,positionOffset從0慢慢過渡到1,往上一張滑動時,positionOffset從1慢慢過渡到0;
- positionOffsetPixels:滑動的像素,從0開始,最大值爲屏幕的寬度(分辨率)
我們這裏主要是在onPageScrolled中對三張圖的背景alpha進行變化,實現我們所需要的效果即可,其他的邏輯大家可以嘗試着改改。
三、最後
我們可以依託ViewPager的屬性實現更多複雜和好看的動畫效果,網上也有很多開源的項目已經做到了,大家可以根據自己的需要進行設置,麼麼噠~