編輯:關於Android編程
記得第一次見到ViewPager這個控件,瞬間愛不釋手,做東西的主界面通通ViewPager,以及圖片切換也拋棄了ImageSwitch之類的,開始讓ViewPager來做。時間長了,ViewPager的切換效果覺得枯燥,形成了審美疲勞~~我們需要改變,今天教大家如何改變ViewPager切換時的效果,實現個性化的圖片切換~~
看一下這樣效果的圖片切換:
是不是比傳統的效果個性很多,嘿嘿~~其實很簡單,學習完這篇博客,保證你可以自定義切換效果,做出各種喪心病狂的切換~~
觀察下效果圖,實際上改變的就是切換時的動畫,那麼簡單了,只需要用戶在切換時,拿到當前的View和下一個View,然後添加動畫是不是就可以了。好,第一步,獲取用戶切換時的當前View和切換至的目的View。
我們在來看一下,如果或者了當前View和目的View,對於動畫我們需要緩慢的變化,最好是根據用戶的手勢滑動。比如上述效果,用戶滑動時,目的圖片根據用戶滑動距離緩緩出現和慢慢變大。好,第二步,設計動畫的梯度變化。
經過分析,我們總結出兩個步驟,下面我們開始一步一步來打造~~~
ViewPager也需要監聽用戶的手勢,所以肯定提供了某個方法。於是縱觀ViewPager的方法,發現了一個叫做onPageScrolled(int position, float positionOffset,int positionOffsetPixels)的方法~~
沒錯就是這個方法:在頁面滾動時調用~
下面仔細研究下這幾個參數:
直接說測試結果:
在非第一頁與最後一頁時,滑動到下一頁,position為當前頁位置;滑動到上一頁:position為當前頁-1
positionOffset滑動到下一頁,[0,1)區間上變化;滑動到上一頁:(1,0]區間上變化
positionOffsetPixels這個和positionOffset很像:滑動到下一頁,[0,寬度)區間上變化;滑動到上一頁:(寬度,0]區間上變化
第一頁時:滑動到上一頁position=0 ,其他基本為0 ;最後一頁滑動到下一頁position為當前頁位置,其他兩個參數為0
豁然發現,我們需要的步驟的第二步解決了,positionOffset很適合作為,漸變,縮放的控制參數;positionOffsetPixels則可以作為平移等的控制參數。
那麼如何獲得當前View和目的View呢:
分享幾個我的歧途:
1、【錯誤】我通過getChildAt(position),getChildAt(position+1),getChildAt(position-1)獲得滑動時,左右的兩個View;乍一看,還真覺得不錯~~~在代碼寫出來,再乍效果也出不來~~錯誤原因:我們忽略一個特別大的東西,ViewPager的機制,滑動時動態加載和刪除View,ViewPager其實只會維持2到3個View,而position的范圍基本屬於無限~~
2、【錯誤】我通過getCurrentItem獲得當前的位置,然後+1,-1獲得後一個或者前一個~~正在竊喜,趕快代碼改過來,效果怎麼也不對,亂七八糟的~~仔細觀察日志,這個getCurrentItem當用戶手指離開的屏幕,Page還在動畫執行時,就改變了~~難怪~整個滑動過程並不是固定的~~唉,心都碎了~
3、【錯誤】position在整個滑動的過程中是不變化的,而且ViewPager會保存2個或3個View;那麼我考慮,如果是第一頁、或者最後一頁那麼我取getChildAt(0)和getChildAt(1),如果在其他頁面則為getChildAt(0),getChildAt(2),然後經過一系列的變化~我想這會總該對了吧,於是我遇到第一問題,第一頁的時候,不管左右position都為0,尼瑪,這哪個為左View,哪個為右View~~
說了這麼多錯誤,大家可以繞過這些彎路,也能從這些彎路裡面看出點什麼~
下面說正確的,其實ViewPager在添加一個View或者銷毀一個View時,是我們自己的PageAdapter中控制的,於是我們可以在ViewPager裡面維系一個HashMap
那麼滑倒下一頁:左邊的View:map.get(position) ,右邊的View : map.get(position+1) .
那麼滑倒上一頁:左邊的View : map.get(position) , 右邊的View : map.get(position+1) , 一樣的,因為滑到上一頁,position為當前頁-1
好了,至此,我們分析了且解決了所有步驟。
MainActivity
[java] view plain copy print?
package com.example.zhy_jazzyviewpager; import android.app.Activity; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ImageView.ScaleType; public class MainActivity extends Activity { protected static final String TAG = "MainActivity"; private int[] mImgIds; private MyJazzyViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImgIds = new int[] { R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d }; mViewPager = (MyJazzyViewPager) findViewById(R.id.id_viewPager); mViewPager.setAdapter(new PagerAdapter() { @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = new ImageView(MainActivity.this); imageView.setImageResource(mImgIds[position]); imageView.setScaleType(ScaleType.CENTER_CROP); container.addView(imageView); mViewPager.setObjectForPosition(imageView, position); return imageView; } @Override public int getCount() { return mImgIds.length; } }); } }
主要看自定義的ViewPager
[java] view plain copy print?
package com.example.zhy_jazzyviewpager; import java.util.HashMap; import java.util.LinkedHashMap; import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.util.Log; import android.view.View; import com.nineoldandroids.view.ViewHelper; public class MyJazzyViewPager extends ViewPager { private float mTrans; private float mScale; /** * 最大的縮小比例 */ private static final float SCALE_MAX = 0.5f; private static final String TAG = "MyJazzyViewPager"; /** * 保存position與對於的View */ private HashMapmChildrenViews = new LinkedHashMap (); /** * 滑動時左邊的元素 */ private View mLeft; /** * 滑動時右邊的元素 */ private View mRight; public MyJazzyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // Log.e(TAG, "position=" + position+", positionOffset = "+positionOffset+" ,positionOffsetPixels = " + positionOffsetPixels+" , currentPos = " + getCurrentItem()); //滑動特別小的距離時,我們認為沒有動,可有可無的判斷 float effectOffset = isSmall(positionOffset) ? 0 : positionOffset; //獲取左邊的View mLeft = findViewFromObject(position); //獲取右邊的View mRight = findViewFromObject(position + 1); // 添加切換動畫效果 animateStack(mLeft, mRight, effectOffset, positionOffsetPixels); super.onPageScrolled(position, positionOffset, positionOffsetPixels); } public void setObjectForPosition(View view, int position) { mChildrenViews.put(position, view); } /** * 通過過位置獲得對應的View * * @param position * @return */ public View findViewFromObject(int position) { return mChildrenViews.get(position); } private boolean isSmall(float positionOffset) { return Math.abs(positionOffset) < 0.0001; } protected void animateStack(View left, View right, float effectOffset, int positionOffsetPixels) { if (right != null) { /** * 縮小比例 如果手指從右到左的滑動(切換到後一個):0.0~1.0,即從一半到最大 * 如果手指從左到右的滑動(切換到前一個):1.0~0,即從最大到一半 */ mScale = (1 - SCALE_MAX) * effectOffset + SCALE_MAX; /** * x偏移量: 如果手指從右到左的滑動(切換到後一個):0-720 如果手指從左到右的滑動(切換到前一個):720-0 */ mTrans = -getWidth() - getPageMargin() + positionOffsetPixels; ViewHelper.setScaleX(right, mScale); ViewHelper.setScaleY(right, mScale); ViewHelper.setTranslationX(right, mTrans); } if (left != null) { left.bringToFront(); } } }
好了,這樣就實現了~~你可以隨便寫自己喜歡的動畫效果,比如在默認上面加個淡入淡出或者神馬,隨便~~是不是很隨意~~
我們的布局文件:
[html] view plain copy print?
其實上面的實現就是github上JazzyViewPager的源碼,用法不用說了,就是我們的MainActivity,它內置了大概10來種效果,我們可以通過代碼或者布局上面設置動畫效果~~我們上面的例子效果,它叫做Stack;
使用JazzViewPager的代碼:其實基本一樣~~最後也會貼上JazzyViewPager的源碼的下載
MainActivity
[java] view plain copy print?
package com.jfeinstein.jazzyviewpager; import com.jfeinstein.jazzyviewpager.JazzyViewPager.TransitionEffect; import android.app.Activity; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ImageView.ScaleType; public class MainActivity extends Activity { protected static final String TAG = "MainActivity"; private int[] mImgIds; private JazzyViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImgIds = new int[] { R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d }; mViewPager = (JazzyViewPager) findViewById(R.id.id_viewPager); //設置切換效果 mViewPager.setTransitionEffect(TransitionEffect.Stack); mViewPager.setAdapter(new PagerAdapter() { @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = new ImageView(MainActivity.this); imageView.setImageResource(mImgIds[position]); imageView.setScaleType(ScaleType.CENTER_CROP); container.addView(imageView); mViewPager.setObjectForPosition(imageView, position); return imageView; } @Override public int getCount() { return mImgIds.length; } }); } }
//設置切換效果
mViewPager.setTransitionEffect(TransitionEffect.Stack);
它有12中可選的切換效果,其實就是寫了12個切換的動畫~~~
好了,最後附上一個我比較喜歡的效果:Tablet
最後,喜歡借此博客拋磚引玉~~大家對感興趣的github上的代碼,可以進行分析與自己嘗試去實現,有時候會發現不是很難~你也可以做到~!
源碼點擊下載
搜芽的移動開發這幾天進度相對來說非常的快。但是美中不足的就是網絡圖片的加載問題。我有兩套方案: 1)沿用迅雷動漫的圖片加載。迅雷動漫也是用的一個開源的庫。但是不知道是我使
前言終究沒有經受住RxJava的誘惑,只恨自己來的比較晚,走起~RxJava 是什麼?一個在 Java VM 上使用可觀測的序列來組成異步的、基於事件的程序的庫~Rx J
以前寫過很多次音樂播放器,但是總有一些問題出現,例如: 1,音樂長時間播放問題(即便是放在service中去播放,依然會被殺死); 2,音樂的播放進度如何掌握?(如何利用
引言對於程序在不同尺寸的Android機器上運行,對UI的適用性造成了額外的開銷,不過限定符的出現,很方便的解決了這個問題。通過創建限定符相關的文件夾來解決資源的加載。限