編輯:關於Android編程
ViewPager作為Android最常用的的組件之一,相信大家在項目中會頻繁的使用到的,例如利用ViewPager制作引導頁、輪播圖,甚至做整個app的表現層的框架等等。
但是在Android 3.0(API 11)以下的ViewPager是比較死板的,不支持動畫特效的,這也就讓ViewPager在切換的時候達不到很好的用戶體驗,下面就是Android3.0以下不添加動畫的ViewPager的實現代碼以及效果演示:
public class MainActivity extends Activity { private ViewPager mViewPager; private int[] imgRes = new int[] { R.drawable.guide_image1, R.drawable.guide_image2, R.drawable.guide_image3 }; private List上面是最簡單的ViewPager使用的Demo,運行如下,看起來很普通很死板:imgList = new ArrayList (); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); mViewPager = (ViewPager) findViewById(R.id.viewpager); mViewPager.setAdapter(new PagerAdapter() { @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public int getCount() { return imgRes.length; } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView mImageView = new ImageView(MainActivity.this); mImageView.setBackgroundResource(imgRes[position]); mImageView.setScaleType(ScaleType.CENTER_CROP); imgList.add(mImageView); container.addView(mImageView); return mImageView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(imgList.get(position)); } }); } }
public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer){...}其中第一個參數boolean類型設置true就好,第二個參數PageTransformer就是我們自定義好的動畫效果:
mViewPager = (ViewPager) findViewById(R.id.viewpager); mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());其中ZoomOutPageTransformer的代碼來自於google的training文檔中,英文好的朋友可以直接進入文檔查看,鏈接是 http://developer.android.com/training/animation/screen-slide.html 源碼如下:
public class ZoomOutPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.85f; private static final float MIN_ALPHA = 0.5f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); int pageHeight = view.getHeight(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 1) { // [-1,1] // Modify the default slide transition to shrink the page as well float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); float vertMargin = pageHeight * (1 - scaleFactor) / 2; float horzMargin = pageWidth * (1 - scaleFactor) / 2; if (position < 0) { view.setTranslationX(horzMargin - vertMargin / 2); } else { view.setTranslationX(-horzMargin + vertMargin / 2); } // Scale the page down (between MIN_SCALE and 1) view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); // Fade the page relative to its size. view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } }另外Google文檔中還提供了另外一個動畫的實現方式,我暫且把源碼附在下面:
public class DepthPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 0) { // [-1,0] // Use the default slide transition when moving to the left page view.setAlpha(1); view.setTranslationX(0); view.setScaleX(1); view.setScaleY(1); } else if (position <= 1) { // (0,1] // Fade the page out. view.setAlpha(1 - position); // Counteract the default slide transition view.setTranslationX(pageWidth * -position); // Scale the page down (between MIN_SCALE and 1) float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } }兩種方式的所實現的效果如下所示,一是ZoomOutPageTransformer,二是DepthPageTransformer
public class DepthPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // view.setAlpha(0); ViewHelper.setAlpha(view, 0); } else if (position <= 0) { // view.setAlpha(1); ViewHelper.setAlpha(view, 1); // view.setTranslationX(0); ViewHelper.setTranslationX(view, 0); // view.setScaleX(1); ViewHelper.setScaleX(view, 1); // view.setScaleY(1); ViewHelper.setScaleY(view, 1); } else if (position <= 1) { // view.setAlpha(1 - position); ViewHelper.setAlpha(view, 1 - position); // view.setTranslationX(pageWidth * -position); ViewHelper.setTranslationX(view, pageWidth * -position); float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); // view.setScaleX(scaleFactor); ViewHelper.setScaleX(view, scaleFactor); // view.setScaleY(scaleFactor); ViewHelper.setScaleY(view, scaleFactor); } else { // view.setAlpha(0); ViewHelper.setAlpha(view, 0); } } }為了好理解,我沒有將Google提供的源碼刪除,而是注釋掉了,方便大家進行比較閱讀,然而即使這樣使用了NineOldAndroids對我們的動畫源碼進行了改造,當我們打開一個Android2.3的模擬器運行一下的時候發現,沒有起到效果,也就是這個動畫效果並沒有執行,在模擬器上運行的ViewPager滑動的效果還是原始默認的左右來回切換的動畫,這又是怎麼回事呢?為止,我們需要打開ViewPager的源碼進行閱讀一下了,既然是在mViewPager.setPageTransformer(true, new DepthPageTransformer());這句代碼沒有起到效果,那麼我們就點進去查看一下setPageTransformer這個方法的源碼,源碼如下:
public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer){ if (Build.VERSION.SDK_INT >= 11) { boolean hasTransformer = transformer != null; boolean needsPopulate = hasTransformer != (this.mPageTransformer != null); this.mPageTransformer = transformer; setChildrenDrawingOrderEnabledCompat(hasTransformer); if (hasTransformer) { this.mDrawingOrder = (reverseDrawingOrder ? 2 : 1); } else { this.mDrawingOrder = 0; } if (needsPopulate) populate(); } }好了,源碼一目了然,我們分析到在ViewPager中的setPageTransFormer這個方法中,首先判斷了一下當前設備的Build.VERSION_SDK_INT>=11,也就是說當前設備是Android3.0以上系統的話,這個方法體執行沒問題,但是若是3.0一下,那就抱歉,無法執行了。知道這個原因之後我們就需要解決這個問題了,我在這裡修改了一下ViewPager的源碼,修改ViewPager的源碼之前,讀者可以先去下載一份ViewPager的源碼,然後拷貝到工程中,重新命名一下,將裡面的if判斷語句給刪除了。以下就是我修改後的部分源碼,命名為ViewPagerCompat:
public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) { // if (Build.VERSION.SDK_INT >= 11) { final boolean hasTransformer = transformer != null; final boolean needsPopulate = hasTransformer != (mPageTransformer != null); mPageTransformer = transformer; setChildrenDrawingOrderEnabledCompat(hasTransformer); if (hasTransformer) { mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; } else { mDrawingOrder = DRAW_ORDER_DEFAULT; } if (needsPopulate) populate(); // } }好,源碼修改完畢,將您的源碼中的ViewPager替換成這個修改後的源碼ViewPagerCompat,那麼ViewPager切換動畫的效果就出現了。
public void transformPage(View view, float position) { ... Log.i(TAG, view = + view + ,position = + position); ... }如上所示,我先在這個方法中打印出方法中的參數view對象和position的值,然後我們來看一下LOG的輸出: 好,我們看LOG輸出日志,可以看到有2個view對象在不停交錯的輸出,其中我選中標注的view的哈希值是4054c260,未選中標注的view的哈希值是4054c548,然後再來看一下position的值,可以注意的是,4054c260的view的position值從0.0一直不斷減小到-1.0,4054c548的view的position的值從1.0一直不斷減小到0.0,我們為了方便,記哈希值為4054c260的view為A頁,記哈希值為4054c548的view為B頁。 情景分析一下,也請一邊看一下DepthPageTransformer.java的源碼; 當position < -1,此時position均不代表A頁和B頁的位置,所以這裡我們不做任何的動畫出來。 當position <= 0,此時position的范圍是在0.0 ~-1.0之間,可以認為這是代表A頁的運動軌跡,也就是A頁移出屏幕外。 當position <= 1,此時position的范圍是在1.0 ~ 0.0之間,可以認為這是代表B頁的運動軌跡,也就是B頁移到屏幕上。 當position > 1,此時position均不代表A頁和B頁的位置,所以這裡我們不做任何的動畫出來。
/** * ViewPager自定義旋轉動畫 * * @author Vincent * */ public class RotateDownTransformer implements PageTransformer { // 旋轉的最大角度為20度 private static final float MAX_ROTATE = 20.0f; // 旋轉過程中的角度 private float currentRotate; @Override public void transformPage(View view, float position) { int pageWidth = view.getWidth(); Log.i(TAG, view = + view + ,position = + position); if (position < -1) { ViewHelper.setRotation(view, 0); } else if (position <= 0) { // position范圍[-1.0,0.0],此時A頁動畫移出屏幕 currentRotate = position * MAX_ROTATE; // 設置當前頁的旋轉中心點,橫坐標是屏幕寬度的1/2,縱坐標為屏幕的高度 ViewHelper.setPivotX(view, pageWidth / 2); ViewHelper.setPivotY(view, view.getHeight()); ViewHelper.setRotation(view, currentRotate); } else if (position <= 1) { // position范圍(0.0,1.0],此時B頁動畫移到屏幕 currentRotate = position * MAX_ROTATE; // 設置當前頁的旋轉中心點,橫坐標是屏幕寬度的1/2,縱坐標為屏幕的高度 ViewHelper.setPivotX(view, pageWidth / 2); ViewHelper.setPivotY(view, view.getHeight()); ViewHelper.setRotation(view, currentRotate); } else { ViewHelper.setRotation(view, 0); } } }效果圖就在上面哦,看起來還湊合吧,根據上面的描述,只要你知道屬性動畫的相關api,也可以自定義初各種各樣的動畫效果出來,可以將多種單一的動畫效果混合在一起使用,讓ViewPager的滑動效果看起來更加的“復雜”。
Android 自定義布局實現氣泡彈窗,可控制氣泡尖角方向及偏移量。效果圖實現首先自定義一個氣泡布局。/** * 氣泡布局 */public class BubbleRe
Android是一個單線程模型,Android界面(UI)的繪制都只能在主線程中進行,如果在主線程中進行耗時的操作,就會影響UI的繪制和事件的響應。所以在android規
年後開始上班甚是清閒,所以想搗鼓一些東西。在翻閱大神傑作Android 教你打造炫酷的ViewPagerIndicator 不僅僅是高仿MIUI的時候看到下面有一條評論說
Bluestacks是一個可以讓Android應用程序運行在電腦(現在包括windows系統,mac版)的一種模擬器,就是我們在電腦上也可以運行Androi