Android进阶:实现android系统自带查看照片动画效果 类似Gallery手势滑动

本文介绍了一种基于Android系统的自定义照片浏览View实现方案。该方案通过自定义View实现了流畅的照片滑动效果,并且能够根据用户滑动的方向切换不同的图片。文章详细介绍了FlingView的实现原理,包括如何处理触摸事件、实现滑动动画等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用的Android系统自带的相机软件,他的照片查看首先是一个Galery,点击查看后也是类似这个效果,感觉体验挺好,仿照效果自己做了下demo


首先看效果:

然后就是加上的滑动动画效果

来看实现:FlingImageDemo

实现主要就是自定义View

  1. importandroid.content.Context;
  2. importandroid.graphics.Bitmap;
  3. importandroid.graphics.Canvas;
  4. importandroid.graphics.Color;
  5. importandroid.graphics.Paint;
  6. importandroid.graphics.Rect;
  7. importandroid.util.AttributeSet;
  8. importandroid.view.View;
  9. importandroid.view.animation.Animation;
  10. importandroid.view.animation.LinearInterpolator;
  11. importandroid.view.animation.Transformation;
  12. /**
  13. *照片浏览View
  14. */
  15. publicclassFlingViewextendsView{
  16. privateBitmapbitmap;
  17. privateBitmapnBitmap;
  18. privateBitmapfBitmap;
  19. publicintOffsetX=0;
  20. publicintOffsetY=0;
  21. publicstaticintpostion=0;
  22. intmLastFlingX=0;
  23. booleanOffsetRight=false;
  24. privateBitmap[]bitmaps;
  25. publicFlingView(Contextcontext,AttributeSetattrs){
  26. super(context,attrs);
  27. }
  28. publicFlingView(Contextcontext,Bitmap[]bitmaps){
  29. super(context);
  30. this.bitmaps=bitmaps;
  31. bitmap=getBitmap(0);
  32. nBitmap=getBitmap(1);
  33. }
  34. @Override
  35. publicvoiddraw(Canvascanvas){
  36. Paintp=newPaint();
  37. canvas.drawColor(Color.BLACK);
  38. if(OffsetX<0){
  39. if(nBitmap!=null){
  40. RectrectTemp=newRect(FlingImageDemo.SCREEN_WIDTH+15+OffsetX,0,FlingImageDemo.SCREEN_WIDTH+15+OffsetX+FlingImageDemo.SCREEN_WIDTH,FlingImageDemo.SCREEN_HEIGHT);
  41. canvas.drawBitmap(nBitmap,null,rectTemp,p);
  42. }
  43. }elseif(OffsetX>0){
  44. if(fBitmap!=null){
  45. RectrectTemp=newRect(-FlingImageDemo.SCREEN_WIDTH-15+OffsetX,0,-FlingImageDemo.SCREEN_WIDTH-15+OffsetX+FlingImageDemo.SCREEN_WIDTH,FlingImageDemo.SCREEN_HEIGHT);
  46. canvas.drawBitmap(fBitmap,null,rectTemp,p);
  47. }
  48. }
  49. if(bitmap!=null){
  50. RectrectTemp=newRect(OffsetX,OffsetY,OffsetX+FlingImageDemo.SCREEN_WIDTH,OffsetY+FlingImageDemo.SCREEN_HEIGHT);
  51. canvas.drawBitmap(bitmap,null,rectTemp,p);
  52. }
  53. }
  54. publicvoidhandleScroll(intdeltaX){
  55. if(deltaX>0){
  56. OffsetX-=-deltaX;
  57. }else{
  58. OffsetX+=deltaX;
  59. }
  60. invalidate();
  61. }
  62. //标记为可以切换到下一张
  63. booleanflag=false;
  64. //标记为需要向右滑动
  65. booleanflag1=false;
  66. //标记为需要向左滑动
  67. booleanflag2=false;
  68. classMyAnimationextendsAnimation{
  69. privateinttemp;
  70. @Override
  71. publicvoidinitialize(intwidth,intheight,intparentWidth,
  72. intparentHeight){
  73. temp=OffsetX;
  74. super.initialize(width,height,parentWidth,parentHeight);
  75. setDuration(500);
  76. setFillAfter(true);
  77. setInterpolator(newLinearInterpolator());
  78. }
  79. @Override
  80. protectedvoidapplyTransformation(floatinterpolatedTime,
  81. Transformationt){
  82. //Log.i("bb","OffsetX==>"+OffsetX);
  83. //需要滑动图片时根据方向来变换OffsetX大小
  84. if(flag){
  85. if(temp>0){
  86. OffsetX=(int)((FlingImageDemo.SCREEN_WIDTH-temp)*interpolatedTime+temp);
  87. }else{
  88. OffsetX=(int)((-FlingImageDemo.SCREEN_WIDTH-temp)*interpolatedTime+temp);
  89. }
  90. //不需要变换的情况
  91. }else{
  92. OffsetX=(int)(temp*(1-interpolatedTime));
  93. }
  94. invalidate();
  95. }
  96. }
  97. //动画结束后需要做一些工作
  98. @Override
  99. protectedvoidonAnimationEnd(){
  100. if(flag1){
  101. nBitmap=bitmap;
  102. bitmap=fBitmap;
  103. fBitmap=null;
  104. postion=postion-1;
  105. }elseif(flag2){
  106. fBitmap=bitmap;
  107. bitmap=nBitmap;
  108. nBitmap=null;
  109. postion=postion+1;
  110. }
  111. flag1=false;
  112. flag2=false;
  113. OffsetX=0;
  114. if(fBitmap==null&&OffsetX==0){
  115. if(postion>0){
  116. fBitmap=getBitmap(postion-1);
  117. }
  118. }elseif(nBitmap==null&&OffsetX==0){
  119. if(postion<bitmaps.length-1){
  120. nBitmap=getBitmap(postion+1);
  121. }
  122. }
  123. clearAnimation();
  124. flag=false;
  125. }
  126. publicvoidonFling(intparamFloat1){
  127. if(OffsetX>FlingImageDemo.SCREEN_WIDTH/3){
  128. if(fBitmap!=null){
  129. flag=true;
  130. flag1=true;
  131. }
  132. }elseif(OffsetX<-FlingImageDemo.SCREEN_WIDTH/3){
  133. if(nBitmap!=null){
  134. flag=true;
  135. flag2=true;
  136. }
  137. }
  138. //开始动画效果
  139. startAnimation(newMyAnimation());
  140. invalidate();
  141. }
  142. /**
  143. *获得当前位置的图片
  144. *@paramcurrentPos
  145. *@return
  146. */
  147. publicBitmapgetBitmap(intcurrentPos){
  148. if(currentPos>bitmaps.length-1){
  149. returnnull;
  150. }
  151. BitmapcurrBitmap=bitmaps[currentPos];
  152. OffsetX=0;
  153. OffsetY=0;
  154. returncurrBitmap;
  155. }
  156. }
import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; /** * 照片浏览View */ public class FlingView extends View{ private Bitmap bitmap; private Bitmap nBitmap; private Bitmap fBitmap; public int OffsetX = 0; public int OffsetY = 0; public static int postion = 0; int mLastFlingX = 0; boolean OffsetRight = false; private Bitmap[] bitmaps ; public FlingView(Context context, AttributeSet attrs) { super(context, attrs); } public FlingView(Context context,Bitmap[] bitmaps){ super(context); this.bitmaps = bitmaps; bitmap = getBitmap(0); nBitmap = getBitmap(1); } @Override public void draw(Canvas canvas) { Paint p = new Paint(); canvas.drawColor(Color.BLACK); if (OffsetX < 0) { if (nBitmap != null) { Rect rectTemp = new Rect(FlingImageDemo.SCREEN_WIDTH+15 + OffsetX,0,FlingImageDemo.SCREEN_WIDTH+15 + OffsetX+FlingImageDemo.SCREEN_WIDTH,FlingImageDemo.SCREEN_HEIGHT); canvas.drawBitmap(nBitmap, null, rectTemp, p); } } else if (OffsetX > 0) { if (fBitmap != null) { Rect rectTemp = new Rect(-FlingImageDemo.SCREEN_WIDTH-15 + OffsetX,0,-FlingImageDemo.SCREEN_WIDTH-15 + OffsetX+FlingImageDemo.SCREEN_WIDTH,FlingImageDemo.SCREEN_HEIGHT); canvas.drawBitmap(fBitmap, null, rectTemp, p); } } if(bitmap != null){ Rect rectTemp = new Rect(OffsetX,OffsetY,OffsetX+FlingImageDemo.SCREEN_WIDTH,OffsetY+FlingImageDemo.SCREEN_HEIGHT); canvas.drawBitmap(bitmap, null, rectTemp, p); } } public void handleScroll(int deltaX) { if (deltaX > 0) { OffsetX -= -deltaX; } else { OffsetX += deltaX; } invalidate(); } //标记为可以切换到下一张 boolean flag = false; //标记为需要向右滑动 boolean flag1 = false; //标记为需要向左滑动 boolean flag2 = false; class MyAnimation extends Animation{ private int temp; @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { temp = OffsetX; super.initialize(width, height, parentWidth, parentHeight); setDuration(500); setFillAfter(true); setInterpolator(new LinearInterpolator()); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { // Log.i("bb", "OffsetX==>"+OffsetX); //需要滑动图片时根据方向来变换OffsetX大小 if(flag){ if(temp>0){ OffsetX = (int) ((FlingImageDemo.SCREEN_WIDTH-temp)*interpolatedTime+temp); }else{ OffsetX = (int) ((-FlingImageDemo.SCREEN_WIDTH-temp)*interpolatedTime+temp); } //不需要变换的情况 }else{ OffsetX = (int) (temp*(1-interpolatedTime)); } invalidate(); } } //动画结束后需要做一些工作 @Override protected void onAnimationEnd() { if (flag1) { nBitmap = bitmap; bitmap = fBitmap; fBitmap = null; postion = postion - 1; } else if (flag2) { fBitmap = bitmap; bitmap = nBitmap; nBitmap = null; postion = postion + 1; } flag1 = false; flag2 = false; OffsetX = 0; if(fBitmap == null && OffsetX == 0){ if (postion > 0) { fBitmap = getBitmap(postion-1); } }else if(nBitmap == null && OffsetX==0){ if (postion < bitmaps.length-1) { nBitmap = getBitmap(postion+1); } } clearAnimation(); flag = false; } public void onFling(int paramFloat1) { if (OffsetX > FlingImageDemo.SCREEN_WIDTH/3) { if (fBitmap != null) { flag = true; flag1 = true; } } else if (OffsetX < -FlingImageDemo.SCREEN_WIDTH/3) { if (nBitmap != null) { flag = true; flag2 = true; } } //开始动画效果 startAnimation(new MyAnimation()); invalidate(); } /** * 获得当前位置的图片 * @param currentPos * @return */ public Bitmap getBitmap(int currentPos) { if (currentPos > bitmaps.length-1) { return null; } Bitmap currBitmap = bitmaps[currentPos]; OffsetX = 0; OffsetY = 0; return currBitmap; } }

中间通过 MyAnimation 来实现自定义的动画 主要重写applyTransformation方法


以及onAnimationEnd方法中 在动画结束后做的一些细节操作了 很简单 就是逻辑搞得有点乱了~~

然后创建Activity 创建View 传入图片资源就OK了

  1. importandroid.app.Activity;
  2. importandroid.graphics.Bitmap;
  3. importandroid.graphics.BitmapFactory;
  4. importandroid.os.Bundle;
  5. importandroid.util.DisplayMetrics;
  6. importandroid.view.GestureDetector;
  7. importandroid.view.MotionEvent;
  8. importandroid.view.GestureDetector.OnGestureListener;
  9. publicclassFlingImageDemoextendsActivityimplementsOnGestureListener{
  10. privateFlingViewflingView;
  11. privateGestureDetectormyGesture;
  12. publicstaticintSCREEN_WIDTH;
  13. publicstaticintSCREEN_HEIGHT;
  14. @Override
  15. publicvoidonCreate(BundlesavedInstanceState){
  16. DisplayMetricsdm=newDisplayMetrics();
  17. getWindowManager().getDefaultDisplay().getMetrics(dm);
  18. //获得手机的宽带和高度像素单位为px
  19. SCREEN_WIDTH=dm.widthPixels;
  20. SCREEN_HEIGHT=dm.heightPixels;
  21. //位图资源不要小于2张
  22. Bitmap[]bitmaps={
  23. BitmapFactory
  24. .decodeResource(getResources(),R.drawable.g1),
  25. BitmapFactory
  26. .decodeResource(getResources(),R.drawable.g3),
  27. BitmapFactory
  28. .decodeResource(getResources(),R.drawable.g4),
  29. //BitmapFactory
  30. //.decodeResource(getResources(),R.drawable.g7),
  31. BitmapFactory
  32. .decodeResource(getResources(),R.drawable.g8)};
  33. super.onCreate(savedInstanceState);
  34. flingView=newFlingView(this,bitmaps);
  35. setContentView(flingView);
  36. myGesture=newGestureDetector(this);
  37. }
  38. @Override
  39. publicbooleanonTouchEvent(MotionEventevent){
  40. switch(event.getAction()){
  41. caseMotionEvent.ACTION_UP:
  42. flingView.onFling(0);
  43. break;
  44. }
  45. returnmyGesture.onTouchEvent(event);
  46. }
  47. @Override
  48. publicbooleanonDown(MotionEvente){
  49. //TODOAuto-generatedmethodstub
  50. returnfalse;
  51. }
  52. //手势完成后调用
  53. @Override
  54. publicbooleanonFling(MotionEvente1,MotionEvente2,floatvelocityX,
  55. floatvelocityY){
  56. flingView.onFling((int)-velocityX);
  57. returntrue;
  58. }
  59. @Override
  60. publicvoidonLongPress(MotionEvente){
  61. //TODOAuto-generatedmethodstub
  62. }
  63. //滑动过程一直在调用
  64. @Override
  65. publicbooleanonScroll(MotionEvente1,MotionEvente2,floatdistanceX,
  66. floatdistanceY){
  67. flingView.handleScroll(-1*(int)distanceX);
  68. returntrue;
  69. }
  70. @Override
  71. publicvoidonShowPress(MotionEvente){
  72. //TODOAuto-generatedmethodstub
  73. }
  74. @Override
  75. publicbooleanonSingleTapUp(MotionEvente){
  76. //TODOAuto-generatedmethodstub
  77. returnfalse;
  78. }
import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.GestureDetector.OnGestureListener; public class FlingImageDemo extends Activity implements OnGestureListener{ private FlingView flingView; private GestureDetector myGesture; public static int SCREEN_WIDTH; public static int SCREEN_HEIGHT; @Override public void onCreate(Bundle savedInstanceState) { DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); //获得手机的宽带和高度像素单位为px SCREEN_WIDTH = dm.widthPixels; SCREEN_HEIGHT = dm.heightPixels; //位图资源 不要小于2张 Bitmap[] bitmaps = { BitmapFactory .decodeResource(getResources(), R.drawable.g1), BitmapFactory .decodeResource(getResources(), R.drawable.g3), BitmapFactory .decodeResource(getResources(), R.drawable.g4), // BitmapFactory // .decodeResource(getResources(), R.drawable.g7), BitmapFactory .decodeResource(getResources(), R.drawable.g8) }; super.onCreate(savedInstanceState); flingView = new FlingView(this,bitmaps); setContentView(flingView); myGesture = new GestureDetector(this); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: flingView.onFling(0); break; } return myGesture.onTouchEvent(event); } @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return false; } //手势完成后调用 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { flingView.onFling((int)-velocityX); return true; } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub } //滑动过程一直在调用 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { flingView.handleScroll(-1*(int)distanceX); return true; } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return false; }

实现OnGestureListener接口 在方法onFling和onScroll中分别调用

import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; /** * 照片浏览View */ public class FlingView extends View{ private Bitmap bitmap; private Bitmap nBitmap; private Bitmap fBitmap; public int OffsetX = 0; public int OffsetY = 0; public static int postion = 0; int mLastFlingX = 0; boolean OffsetRight = false; private Bitmap[] bitmaps ; public FlingView(Context context, AttributeSet attrs) { super(context, attrs); } public FlingView(Context context,Bitmap[] bitmaps){ super(context); this.bitmaps = bitmaps; bitmap = getBitmap(0); nBitmap = getBitmap(1); } @Override public void draw(Canvas canvas) { Paint p = new Paint(); canvas.drawColor(Color.BLACK); if (OffsetX < 0) { if (nBitmap != null) { Rect rectTemp = new Rect(FlingImageDemo.SCREEN_WIDTH+15 + OffsetX,0,FlingImageDemo.SCREEN_WIDTH+15 + OffsetX+FlingImageDemo.SCREEN_WIDTH,FlingImageDemo.SCREEN_HEIGHT); canvas.drawBitmap(nBitmap, null, rectTemp, p); } } else if (OffsetX > 0) { if (fBitmap != null) { Rect rectTemp = new Rect(-FlingImageDemo.SCREEN_WIDTH-15 + OffsetX,0,-FlingImageDemo.SCREEN_WIDTH-15 + OffsetX+FlingImageDemo.SCREEN_WIDTH,FlingImageDemo.SCREEN_HEIGHT); canvas.drawBitmap(fBitmap, null, rectTemp, p); } } if(bitmap != null){ Rect rectTemp = new Rect(OffsetX,OffsetY,OffsetX+FlingImageDemo.SCREEN_WIDTH,OffsetY+FlingImageDemo.SCREEN_HEIGHT); canvas.drawBitmap(bitmap, null, rectTemp, p); } } public void handleScroll(int deltaX) { if (deltaX > 0) { OffsetX -= -deltaX; } else { OffsetX += deltaX; } invalidate(); } //标记为可以切换到下一张 boolean flag = false; //标记为需要向右滑动 boolean flag1 = false; //标记为需要向左滑动 boolean flag2 = false; class MyAnimation extends Animation{ private int temp; @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { temp = OffsetX; super.initialize(width, height, parentWidth, parentHeight); setDuration(500); setFillAfter(true); setInterpolator(new LinearInterpolator()); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { // Log.i("bb", "OffsetX==>"+OffsetX); //需要滑动图片时根据方向来变换OffsetX大小 if(flag){ if(temp>0){ OffsetX = (int) ((FlingImageDemo.SCREEN_WIDTH-temp)*interpolatedTime+temp); }else{ OffsetX = (int) ((-FlingImageDemo.SCREEN_WIDTH-temp)*interpolatedTime+temp); } //不需要变换的情况 }else{ OffsetX = (int) (temp*(1-interpolatedTime)); } invalidate(); } } //动画结束后需要做一些工作 @Override protected void onAnimationEnd() { if (flag1) { nBitmap = bitmap; bitmap = fBitmap; fBitmap = null; postion = postion - 1; } else if (flag2) { fBitmap = bitmap; bitmap = nBitmap; nBitmap = null; postion = postion + 1; } flag1 = false; flag2 = false; OffsetX = 0; if(fBitmap == null && OffsetX == 0){ if (postion > 0) { fBitmap = getBitmap(postion-1); } }else if(nBitmap == null && OffsetX==0){ if (postion < bitmaps.length-1) { nBitmap = getBitmap(postion+1); } } clearAnimation(); flag = false; } public void onFling(int paramFloat1) { if (OffsetX > FlingImageDemo.SCREEN_WIDTH/3) { if (fBitmap != null) { flag = true; flag1 = true; } } else if (OffsetX < -FlingImageDemo.SCREEN_WIDTH/3) { if (nBitmap != null) { flag = true; flag2 = true; } } //开始动画效果 startAnimation(new MyAnimation()); invalidate(); } /** * 获得当前位置的图片 * @param currentPos * @return */ public Bitmap getBitmap(int currentPos) { if (currentPos > bitmaps.length-1) { return null; } Bitmap currBitmap = bitmaps[currentPos]; OffsetX = 0; OffsetY = 0; return currBitmap; } } import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.GestureDetector.OnGestureListener; public class FlingImageDemo extends Activity implements OnGestureListener{ private FlingView flingView; private GestureDetector myGesture; public static int SCREEN_WIDTH; public static int SCREEN_HEIGHT; @Override public void onCreate(Bundle savedInstanceState) { DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); //获得手机的宽带和高度像素单位为px SCREEN_WIDTH = dm.widthPixels; SCREEN_HEIGHT = dm.heightPixels; //位图资源 不要小于2张 Bitmap[] bitmaps = { BitmapFactory .decodeResource(getResources(), R.drawable.g1), BitmapFactory .decodeResource(getResources(), R.drawable.g3), BitmapFactory .decodeResource(getResources(), R.drawable.g4), // BitmapFactory // .decodeResource(getResources(), R.drawable.g7), BitmapFactory .decodeResource(getResources(), R.drawable.g8) }; super.onCreate(savedInstanceState); flingView = new FlingView(this,bitmaps); setContentView(flingView); myGesture = new GestureDetector(this); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: flingView.onFling(0); break; } return myGesture.onTouchEvent(event); } @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return false; } //手势完成后调用 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { flingView.onFling((int)-velocityX); return true; } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub } //滑动过程一直在调用 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { flingView.handleScroll(-1*(int)distanceX); return true; } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return false; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值