总结一些 android 平常用到的自定义控件

博客转载自:http://blog.csdn.net/kongbaidepao/article/details/22267679

1.阻尼效果listview

[java]  view plain copy
  1. public class MyListView extends ListView implements Runnable {  
  2.       
  3.     private float mLastDownY = 0f;   
  4.     private int mDistance = 0;   
  5.     private int mStep = 10;   
  6.     private boolean mPositive = false;   
  7.    
  8.   
  9.     public MyListView (Context context, AttributeSet attrs) {   
  10.           super(context, attrs);   
  11.     }   
  12.    
  13.     public MyListView (Context context, AttributeSet attrs, int defStyle) {   
  14.           super(context, attrs, defStyle);   
  15.     }   
  16.    
  17.     public MyListView (Context context) {   
  18.           super(context);   
  19.     }   
  20.    
  21.       
  22.     @Override   
  23.     public boolean onTouchEvent(MotionEvent event) {   
  24.          switch (event.getAction()) {   
  25.               case MotionEvent.ACTION_DOWN:   
  26.                    if (mLastDownY == 0f && mDistance == 0) {   
  27.                          mLastDownY = event.getY();   
  28.                    return true;   
  29.               }   
  30.               break;   
  31.            
  32.               case MotionEvent.ACTION_CANCEL:   
  33.                    break;  
  34.           
  35.               case MotionEvent.ACTION_UP:   
  36.                   if (mDistance != 0) {   
  37.                    mStep = 1;   
  38.                    mPositive = (mDistance >= 0);   
  39.                    this.post(this);   
  40.                    return true;   
  41.                 }   
  42.                  mLastDownY = 0f;   
  43.                  mDistance = 0;   
  44.                  break;   
  45.            
  46.               case MotionEvent.ACTION_MOVE:   
  47.                  if (mLastDownY != 0f) {   
  48.                       mDistance = (int) (mLastDownY - event.getY());   
  49.                       if ((mDistance < 0 && getFirstVisiblePosition() == 0 && getChildAt(0).getTop() == 0) || (mDistance > 0 && getLastVisiblePosition() == getCount() - 1)) {   
  50.                            mDistance /= 2;   
  51.                            scrollTo(0, mDistance);   
  52.                            return true;   
  53.                        }   
  54.                 }   
  55.         mDistance = 0;   
  56.         break;   
  57.         }   
  58.         return super.onTouchEvent(event);   
  59.     }   
  60.    
  61.     public void run() {   
  62.           mDistance += mDistance > 0 ? -mStep : mStep;   
  63.           scrollTo(0, mDistance);   
  64.           if ((mPositive && mDistance <= 0) || (!mPositive && mDistance >= 0)) {   
  65.                 scrollTo(00);   
  66.                 mDistance = 0;   
  67.                 mLastDownY = 0f;   
  68.                 return;   
  69.            }   
  70.           mStep += 1;   
  71.           this.postDelayed(this10);   
  72.      }   
  73. }   

2.阻尼效果 scrollview

[java]  view plain copy
  1. public class CustomScrollView extends ScrollView {  
  2.   
  3.     private View inner;// 孩子View  
  4.   
  5.     private float y;// 点击时y坐标  
  6.   
  7.     private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)  
  8.   
  9.     private boolean isCount = false;// 是否开始计算  
  10.   
  11.     private boolean isMoveing = false;// 是否开始移动.  
  12.   
  13.     private ImageView imageView;  
  14.   
  15.     private int initTop, initbottom;// 初始高度  
  16.     private int top, bottom;// 拖动时时高度。  
  17.   
  18.     public void setImageView(ImageView imageView) {  
  19.         this.imageView = imageView;  
  20.     }  
  21.   
  22.     public CustomScrollView(Context context, AttributeSet attrs) {  
  23.         super(context, attrs);  
  24.     }  
  25.   
  26.     /*** 
  27.      * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate 
  28.      * 方法,也应该调用父类的方法,使该方法得以执行. 
  29.      */  
  30.     @Override  
  31.     protected void onFinishInflate() {  
  32.         if (getChildCount() > 0) {  
  33.             inner = getChildAt(0);  
  34.         }  
  35.     }  
  36.   
  37.     /** touch 事件处理 **/  
  38.     @Override  
  39.     public boolean onTouchEvent(MotionEvent ev) {  
  40.         if (inner != null) {  
  41.             commOnTouchEvent(ev);  
  42.         }  
  43.         return super.onTouchEvent(ev);  
  44.     }  
  45.   
  46.     /*** 
  47.      * 触摸事件 
  48.      *  
  49.      * @param ev 
  50.      */  
  51.     public void commOnTouchEvent(MotionEvent ev) {  
  52.         int action = ev.getAction();  
  53.         switch (action) {  
  54.         case MotionEvent.ACTION_DOWN:  
  55.             top = initTop = imageView.getTop();  
  56.             bottom = initbottom = imageView.getBottom();  
  57.             break;  
  58.   
  59.         case MotionEvent.ACTION_UP:  
  60.   
  61.             isMoveing = false;  
  62.             // 手指松开.  
  63.             if (isNeedAnimation()) {  
  64.   
  65.                 animation();  
  66.   
  67.             }  
  68.             break;  
  69.         /*** 
  70.          * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到, 
  71.          * 因为此时是MyScrollView的touch事件传递到到了LIstView的孩子item上面.所以从第二次计算开始. 
  72.          * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行. 
  73.          */  
  74.         case MotionEvent.ACTION_MOVE:  
  75.   
  76.             final float preY = y;// 按下时的y坐标  
  77.   
  78.             float nowY = ev.getY();// 时时y坐标  
  79.             int deltaY = (int) (nowY - preY);// 滑动距离  
  80.             if (!isCount) {  
  81.                 deltaY = 0// 在这里要归0.  
  82.             }  
  83.   
  84.             if (deltaY < 0 && top <= initTop)  
  85.                 return;  
  86.   
  87.             // 当滚动到最上或者最下时就不会再滚动,这时移动布局  
  88.             isNeedMove();  
  89.   
  90.             if (isMoveing) {  
  91.                 // 初始化头部矩形  
  92.                 if (normal.isEmpty()) {  
  93.                     // 保存正常的布局位置  
  94.                     normal.set(inner.getLeft(), inner.getTop(),  
  95.                             inner.getRight(), inner.getBottom());  
  96.                 }  
  97.   
  98.                 // 移动布局  
  99.                 inner.layout(inner.getLeft(), inner.getTop() + deltaY / 3,  
  100.                         inner.getRight(), inner.getBottom() + deltaY / 3);  
  101.   
  102.                 top += (deltaY / 6);  
  103.                 bottom += (deltaY / 6);  
  104.                 imageView.layout(imageView.getLeft(), top,  
  105.                         imageView.getRight(), bottom);  
  106.             }  
  107.   
  108.             isCount = true;  
  109.             y = nowY;  
  110.             break;  
  111.   
  112.         default:  
  113.             break;  
  114.   
  115.         }  
  116.     }  
  117.   
  118.     /*** 
  119.      * 回缩动画 
  120.      */  
  121.     public void animation() {  
  122.   
  123.         TranslateAnimation taa = new TranslateAnimation(00, top + 200,  
  124.                 initTop + 200);  
  125.         taa.setDuration(200);  
  126.         imageView.startAnimation(taa);  
  127.         imageView.layout(imageView.getLeft(), initTop, imageView.getRight(),  
  128.                 initbottom);  
  129.   
  130.         // 开启移动动画  
  131.         TranslateAnimation ta = new TranslateAnimation(00, inner.getTop(),  
  132.                 normal.top);  
  133.         ta.setDuration(200);  
  134.         inner.startAnimation(ta);  
  135.         // 设置回到正常的布局位置  
  136.         inner.layout(normal.left, normal.top, normal.right, normal.bottom);  
  137.         normal.setEmpty();  
  138.   
  139.         isCount = false;  
  140.         y = 0;// 手指松开要归0.  
  141.   
  142.     }  
  143.   
  144.     // 是否需要开启动画  
  145.     public boolean isNeedAnimation() {  
  146.         return !normal.isEmpty();  
  147.     }  
  148.   
  149.     /*** 
  150.      * 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度 
  151.      *  
  152.      * getHeight():获取的是屏幕的高度 
  153.      *  
  154.      * @return 
  155.      */  
  156.     public void isNeedMove() {  
  157.         int offset = inner.getMeasuredHeight() - getHeight();  
  158.         int scrollY = getScrollY();  
  159.         // Log.e("jj", "scrolly=" + scrollY);  
  160.         // 0是顶部,后面那个是底部  
  161.         if (scrollY == 0 || scrollY == offset) {  
  162.             isMoveing = true;  
  163.         }  
  164.     }  
  165.   
  166. }  


3. 保证长宽比 缩放使图片不失真的 imageview

[java]  view plain copy
  1. public class RoundedImageView extends ImageView {  
  2.   
  3.     public RoundedImageView(Context context) {  
  4.         super(context);  
  5.         // TODO Auto-generated constructor stub  
  6.     }  
  7.   
  8.     public RoundedImageView(Context context, AttributeSet attrs) {  
  9.         super(context, attrs);  
  10.     }  
  11.   
  12.     public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {  
  13.         super(context, attrs, defStyle);  
  14.     }  
  15.   
  16.     @Override  
  17.     protected void onDraw(Canvas canvas) {  
  18.   
  19.         Drawable drawable = getDrawable();  
  20.   
  21.         if (drawable == null) {  
  22.             return;  
  23.         }  
  24.   
  25.         if (getWidth() == 0 || getHeight() == 0) {  
  26.             return;  
  27.         }  
  28.         Bitmap b = ((BitmapDrawable) drawable).getBitmap();  
  29.         Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);  
  30.   
  31.         int w = getWidth(), h = getHeight();  
  32.   
  33.         Bitmap roundBitmap = getCroppedBitmap(bitmap, w);  
  34.         canvas.drawBitmap(roundBitmap, 00null);  
  35.   
  36.     }  
  37.   
  38.       
  39.     public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {  
  40.         Bitmap sbmp;  
  41.         if (bmp.getWidth() != radius || bmp.getHeight() != radius)  
  42.             sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);  
  43.         else  
  44.             sbmp = bmp;  
  45.         Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),  
  46.                 Config.ARGB_8888);  
  47.         Canvas canvas = new Canvas(output);  
  48.   
  49.         final int color = 0xffa19774;  
  50.         final Paint paint = new Paint();  
  51.         final Rect rect = new Rect(00, sbmp.getWidth(), sbmp.getHeight());  
  52.   
  53.         paint.setAntiAlias(true);  
  54.         paint.setFilterBitmap(true);  
  55.         paint.setDither(true);  
  56.         canvas.drawARGB(0000);  
  57.         paint.setColor(Color.parseColor("#BAB399"));  
  58.         canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f,  
  59.                 sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);  
  60.         paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));  
  61.         canvas.drawBitmap(sbmp, rect, rect, paint);  
  62.   
  63.         return output;  
  64.     }  
  65.   
  66. }  
比如 设置 imageview的 w,h

[html]  view plain copy
  1. <com.example.view.RoundedImageView  
  2.            android:layout_width="wrap_content"  
  3.            android:layout_height="wrap_content"  
  4.            android:layout_gravity="center_horizontal"  
  5.            android:adjustViewBounds="true"  
  6.            android:maxHeight="80dip"  
  7.            android:maxWidth="80dip"  
  8.            android:src="@drawable/aa" />  


3.开关按钮(为了兼容版本)


[java]  view plain copy
  1. public class SlidButton extends View implements OnTouchListener {    
  2.     
  3.     private boolean nowChoose = false;// 记录当前按钮是否打开,true为打开,false为关闭    
  4.     private boolean onSlip = false;// 记录用户是否在滑动    
  5.     private float   downX, nowX; // 按下时的x,当前的x    
  6.     private Rect    btn_on, btn_off;// 打开和关闭状态下,游标的Rect    
  7.     
  8.     private boolean isChgLsnOn = false;//是否设置监听    
  9.     private OnChangedListener changedLis;    
  10.       
  11.     int begin,end;//控件当前的位置  
  12.     private Bitmap bg_on, bg_off, slip_btn;    
  13.     
  14.     public SlidButton(Context context, AttributeSet attrs) {    
  15.         super(context, attrs);    
  16.         init();    
  17.     }    
  18.     
  19.     public SlidButton(Context context) {    
  20.         super(context);    
  21.         init();    
  22.     }    
  23.     
  24.         
  25.     private void init() {    
  26.         // 载入图片资源    
  27.         bg_on = BitmapFactory.decodeResource(getResources(),    
  28.                 R.drawable.sild_bg_on1);    
  29.         bg_off = BitmapFactory.decodeResource(getResources(),    
  30.                 R.drawable.sild_bg_off1);    
  31.         slip_btn = BitmapFactory.decodeResource(getResources(),    
  32.                 R.drawable.sild_bg_btn1);    
  33.           
  34.           
  35.         // 获得需要的Rect数据    
  36.         btn_on = new Rect(00, slip_btn.getWidth() , slip_btn.getHeight());    
  37.         btn_off = new Rect(bg_off.getWidth() - slip_btn.getWidth(), 0,    
  38.                 bg_off.getWidth(), slip_btn.getHeight());    
  39.         setOnTouchListener(this);    
  40.     }    
  41.       
  42.       
  43.       
  44.     @Override    
  45.     protected void onDraw(Canvas canvas) {    
  46.         super.onDraw(canvas);    
  47.         Matrix matrix = new Matrix();   
  48.         begin           =this.getWidth() - bg_off.getWidth();  
  49.         end             =9;  
  50.         matrix.postTranslate(begin, end);  
  51.         Paint paint = new Paint();    
  52.         float x;    
  53.             
  54.         {    
  55. //            if (nowX<(bg_on.getWidth()/2)) //滑动到前半段与后半段的背景不同,在此做判断    
  56.             if(!nowChoose){  
  57.                   
  58.                  canvas.drawBitmap(bg_off, matrix, paint);//画出关闭时的背景    
  59.             }else{  
  60.                  canvas.drawBitmap(bg_on, matrix, paint);//画出打开时的背景     
  61.             }    
  62.                  
  63.                     
  64.             if (onSlip) {//是否是在滑动状态,      
  65.                 if(nowX >= bg_on.getWidth()){  
  66.                     //是否划出指定范围,不能让游标跑到外头,必须做这个判断    
  67.                    x = bg_on.getWidth() - slip_btn.getWidth()/2;//减去游标1/2的长度    
  68.                   
  69.                 }else{  
  70.                    x = nowX - slip_btn.getWidth() / 2;        
  71.                 }    
  72.                      
  73.              
  74.             }else {    
  75.                 if(nowChoose)//根据现在的开关状态设置画游标的位置     
  76.                     x = btn_off.left;    
  77.                 else    
  78.                     x = btn_on.left;    
  79.             }    
  80.                 
  81.             if (x < 0 ) //对游标位置进行异常判断..    
  82.                 x = 0;    
  83.             else if(x > bg_on.getWidth() - slip_btn.getWidth())    
  84.                 x = bg_on.getWidth() - slip_btn.getWidth();    
  85.                 
  86.             canvas.drawBitmap(slip_btn, x + begin, end, paint);//画出游标.       
  87.         }    
  88.     }    
  89.     
  90.       
  91.       
  92.     @Override    
  93.     public boolean onTouch(View v, MotionEvent event) {    
  94.             
  95.         switch (event.getAction()) {//根据动作来执行代码    
  96.                 
  97.             case MotionEvent.ACTION_MOVE:  
  98.                 nowX = event.getX();    
  99.                 break;    
  100.              
  101.             case MotionEvent.ACTION_DOWN:    
  102.                 if (event.getX() < begin)     
  103.                     return false;    
  104.                 onSlip = true;    
  105.                 downX = event.getX();    
  106.                 nowX = downX;    
  107.                 break;    
  108.               
  109.             case MotionEvent.ACTION_UP://松开    
  110.                 onSlip = false;    
  111.                 boolean lastChoose = nowChoose;    
  112.                 /*if (event.getX() >= begin+(bg_on.getWidth()/2))    
  113.                     nowChoose = true;   
  114.                 else    
  115.                     nowChoose = false; */   
  116.                 nowChoose       =!nowChoose;  
  117.                 if(isChgLsnOn && (lastChoose != nowChoose))//如果设置了监听器,就调用其方法.    
  118.                     changedLis.OnChanged(nowChoose);    
  119.                 break;    
  120.             default:    
  121.                 break;    
  122.         }    
  123.         invalidate();    
  124.         return true;    
  125.     }    
  126.     
  127.         
  128.     public void SetOnChangedListener(OnChangedListener l){//设置监听器,当状态修改的时候    
  129.         isChgLsnOn = true;    
  130.         changedLis = l;    
  131.     }    
  132.         
  133.     public interface OnChangedListener {    
  134.         abstract void OnChanged(boolean checkState);    
  135.     }    
  136. }  

[html]  view plain copy
  1. <com.view.SlidButton  
  2.     android:layout_width="50dip"  
  3.     android:layout_height="30dp"  
  4.     />   

4. 缩小放大图片

[java]  view plain copy
  1. public class TouchImageView extends ImageView {  
  2.   
  3.     Matrix matrix;  
  4.   
  5.     // We can be in one of these 3 states  
  6.     static final int NONE = 0;  
  7.     static final int DRAG = 1;  
  8.     static final int ZOOM = 2;  
  9.     int mode = NONE;  
  10.   
  11.     // Remember some things for zooming  
  12.     PointF last = new PointF();  
  13.     PointF start = new PointF();  
  14.     float minScale = 1f;  
  15.     float maxScale = 3f;  
  16.     float[] m;  
  17.   
  18.   
  19.     int viewWidth, viewHeight;  
  20.     static final int CLICK = 3;  
  21.     float saveScale = 1f;  
  22.     protected float origWidth, origHeight;  
  23.     int oldMeasuredWidth, oldMeasuredHeight;  
  24.   
  25.   
  26.     ScaleGestureDetector mScaleDetector;  
  27.   
  28.     Context context;  
  29.   
  30.     public TouchImageView(Context context) {  
  31.         super(context);  
  32.         sharedConstructing(context);  
  33.     }  
  34.   
  35.     public TouchImageView(Context context, AttributeSet attrs) {  
  36.         super(context, attrs);  
  37.         sharedConstructing(context);  
  38.     }  
  39.       
  40.     private void sharedConstructing(Context context) {  
  41.         super.setClickable(true);  
  42.         this.context = context;  
  43.         mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());  
  44.         matrix = new Matrix();  
  45.         m = new float[9];  
  46.         setImageMatrix(matrix);  
  47.         setScaleType(ScaleType.MATRIX);  
  48.   
  49.         setOnTouchListener(new OnTouchListener() {  
  50.   
  51.             @Override  
  52.             public boolean onTouch(View v, MotionEvent event) {  
  53.                 mScaleDetector.onTouchEvent(event);  
  54.                 PointF curr = new PointF(event.getX(), event.getY());  
  55.   
  56.                 switch (event.getAction()) {  
  57.                     case MotionEvent.ACTION_DOWN:  
  58.                         last.set(curr);  
  59.                         start.set(last);  
  60.                         mode = DRAG;  
  61.                         break;  
  62.                           
  63.                     case MotionEvent.ACTION_MOVE:  
  64.                         if (mode == DRAG) {  
  65.                             float deltaX = curr.x - last.x;  
  66.                             float deltaY = curr.y - last.y;  
  67.                             float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);  
  68.                             float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);  
  69.                             matrix.postTranslate(fixTransX, fixTransY);  
  70.                             fixTrans();  
  71.                             last.set(curr.x, curr.y);  
  72.                         }  
  73.                         break;  
  74.   
  75.                     case MotionEvent.ACTION_UP:  
  76.                         mode = NONE;  
  77.                         int xDiff = (int) Math.abs(curr.x - start.x);  
  78.                         int yDiff = (int) Math.abs(curr.y - start.y);  
  79.                         if (xDiff < CLICK && yDiff < CLICK)  
  80.                             performClick();  
  81.                         break;  
  82.   
  83.                     case MotionEvent.ACTION_POINTER_UP:  
  84.                         mode = NONE;  
  85.                         break;  
  86.                 }  
  87.                   
  88.                 setImageMatrix(matrix);  
  89.                 invalidate();  
  90.                 return true// indicate event was handled  
  91.             }  
  92.   
  93.         });  
  94.     }  
  95.   
  96.     public void setMaxZoom(float x) {  
  97.         maxScale = x;  
  98.     }  
  99.   
  100.     private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {  
  101.         @Override  
  102.         public boolean onScaleBegin(ScaleGestureDetector detector) {  
  103.             mode = ZOOM;  
  104.             return true;  
  105.         }  
  106.   
  107.         @Override  
  108.         public boolean onScale(ScaleGestureDetector detector) {  
  109.             float mScaleFactor = detector.getScaleFactor();  
  110.             float origScale = saveScale;  
  111.             saveScale *= mScaleFactor;  
  112.             if (saveScale > maxScale) {  
  113.                 saveScale = maxScale;  
  114.                 mScaleFactor = maxScale / origScale;  
  115.             } else if (saveScale < minScale) {  
  116.                 saveScale = minScale;  
  117.                 mScaleFactor = minScale / origScale;  
  118.             }  
  119.   
  120.             if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight)  
  121.                 matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2);  
  122.             else  
  123.                 matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());  
  124.   
  125.             fixTrans();  
  126.             return true;  
  127.         }  
  128.     }  
  129.   
  130.     void fixTrans() {  
  131.         matrix.getValues(m);  
  132.         float transX = m[Matrix.MTRANS_X];  
  133.         float transY = m[Matrix.MTRANS_Y];  
  134.           
  135.         float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);  
  136.         float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);  
  137.   
  138.         if (fixTransX != 0 || fixTransY != 0)  
  139.             matrix.postTranslate(fixTransX, fixTransY);  
  140.     }  
  141.   
  142.     float getFixTrans(float trans, float viewSize, float contentSize) {  
  143.         float minTrans, maxTrans;  
  144.   
  145.         if (contentSize <= viewSize) {  
  146.             minTrans = 0;  
  147.             maxTrans = viewSize - contentSize;  
  148.         } else {  
  149.             minTrans = viewSize - contentSize;  
  150.             maxTrans = 0;  
  151.         }  
  152.   
  153.         if (trans < minTrans)  
  154.             return -trans + minTrans;  
  155.         if (trans > maxTrans)  
  156.             return -trans + maxTrans;  
  157.         return 0;  
  158.     }  
  159.       
  160.     float getFixDragTrans(float delta, float viewSize, float contentSize) {  
  161.         if (contentSize <= viewSize) {  
  162.             return 0;  
  163.         }  
  164.         return delta;  
  165.     }  
  166.   
  167.     @Override  
  168.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  169.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  170.         viewWidth = MeasureSpec.getSize(widthMeasureSpec);  
  171.         viewHeight = MeasureSpec.getSize(heightMeasureSpec);  
  172.           
  173.         //  
  174.         // Rescales image on rotation  
  175.         //  
  176.         if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight  
  177.                 || viewWidth == 0 || viewHeight == 0)  
  178.             return;  
  179.         oldMeasuredHeight = viewHeight;  
  180.         oldMeasuredWidth = viewWidth;  
  181.   
  182.         if (saveScale == 1) {  
  183.             //Fit to screen.  
  184.             float scale;  
  185.   
  186.             Drawable drawable = getDrawable();  
  187.             if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0)  
  188.                 return;  
  189.             int bmWidth = drawable.getIntrinsicWidth();  
  190.             int bmHeight = drawable.getIntrinsicHeight();  
  191.               
  192.             Log.d("bmSize""bmWidth: " + bmWidth + " bmHeight : " + bmHeight);  
  193.   
  194.             float scaleX = (float) viewWidth / (float) bmWidth;  
  195.             float scaleY = (float) viewHeight / (float) bmHeight;  
  196.             scale = Math.min(scaleX, scaleY);  
  197.             matrix.setScale(scale, scale);  
  198.   
  199.             // Center the image  
  200.             float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);  
  201.             float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);  
  202.             redundantYSpace /= (float2;  
  203.             redundantXSpace /= (float2;  
  204.   
  205.             matrix.postTranslate(redundantXSpace, redundantYSpace);  
  206.   
  207.             origWidth = viewWidth - 2 * redundantXSpace;  
  208.             origHeight = viewHeight - 2 * redundantYSpace;  
  209.             setImageMatrix(matrix);  
  210.         }  
  211.         fixTrans();  
  212.     }  
  213. }  

[java]  view plain copy
  1. public class TouchImageViewActivity extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.main);  
  7.         TouchImageView img = (TouchImageView) findViewById(R.id.snoop);  
  8.         img.setImageResource(R.drawable.snoopy);  
  9.         img.setMaxZoom(4f);  
  10.     }  
  11. }  

[java]  view plain copy
  1. /** 
  2.  * 自定义的ImageView控制,可对图片进行多点触控缩放和拖动 
  3.  *  
  4.  * @author guolin 
  5.  */  
  6. public class ZoomImageView extends View {  
  7.   
  8.     /** 
  9.      * 初始化状态常量 
  10.      */  
  11.     public static final int STATUS_INIT = 1;  
  12.   
  13.     /** 
  14.      * 图片放大状态常量 
  15.      */  
  16.     public static final int STATUS_ZOOM_OUT = 2;  
  17.   
  18.     /** 
  19.      * 图片缩小状态常量 
  20.      */  
  21.     public static final int STATUS_ZOOM_IN = 3;  
  22.   
  23.     /** 
  24.      * 图片拖动状态常量 
  25.      */  
  26.     public static final int STATUS_MOVE = 4;  
  27.   
  28.     /** 
  29.      * 用于对图片进行移动和缩放变换的矩阵 
  30.      */  
  31.     private Matrix matrix = new Matrix();  
  32.   
  33.     /** 
  34.      * 待展示的Bitmap对象 
  35.      */  
  36.     private Bitmap sourceBitmap;  
  37.   
  38.     /** 
  39.      * 记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE 
  40.      */  
  41.     private int currentStatus;  
  42.   
  43.     /** 
  44.      * ZoomImageView控件的宽度 
  45.      */  
  46.     private int width;  
  47.   
  48.     /** 
  49.      * ZoomImageView控件的高度 
  50.      */  
  51.     private int height;  
  52.   
  53.     /** 
  54.      * 记录两指同时放在屏幕上时,中心点的横坐标值 
  55.      */  
  56.     private float centerPointX;  
  57.   
  58.     /** 
  59.      * 记录两指同时放在屏幕上时,中心点的纵坐标值 
  60.      */  
  61.     private float centerPointY;  
  62.   
  63.     /** 
  64.      * 记录当前图片的宽度,图片被缩放时,这个值会一起变动 
  65.      */  
  66.     private float currentBitmapWidth;  
  67.   
  68.     /** 
  69.      * 记录当前图片的高度,图片被缩放时,这个值会一起变动 
  70.      */  
  71.     private float currentBitmapHeight;  
  72.   
  73.     /** 
  74.      * 记录上次手指移动时的横坐标 
  75.      */  
  76.     private float lastXMove = -1;  
  77.   
  78.     /** 
  79.      * 记录上次手指移动时的纵坐标 
  80.      */  
  81.     private float lastYMove = -1;  
  82.   
  83.     /** 
  84.      * 记录手指在横坐标方向上的移动距离 
  85.      */  
  86.     private float movedDistanceX;  
  87.   
  88.     /** 
  89.      * 记录手指在纵坐标方向上的移动距离 
  90.      */  
  91.     private float movedDistanceY;  
  92.   
  93.     /** 
  94.      * 记录图片在矩阵上的横向偏移值 
  95.      */  
  96.     private float totalTranslateX;  
  97.   
  98.     /** 
  99.      * 记录图片在矩阵上的纵向偏移值 
  100.      */  
  101.     private float totalTranslateY;  
  102.   
  103.     /** 
  104.      * 记录图片在矩阵上的总缩放比例 
  105.      */  
  106.     private float totalRatio;  
  107.   
  108.     /** 
  109.      * 记录手指移动的距离所造成的缩放比例 
  110.      */  
  111.     private float scaledRatio;  
  112.   
  113.     /** 
  114.      * 记录图片初始化时的缩放比例 
  115.      */  
  116.     private float initRatio;  
  117.   
  118.     /** 
  119.      * 记录上次两指之间的距离 
  120.      */  
  121.     private double lastFingerDis;  
  122.   
  123.     /** 
  124.      * ZoomImageView构造函数,将当前操作状态设为STATUS_INIT。 
  125.      *  
  126.      * @param context 
  127.      * @param attrs 
  128.      */  
  129.     public ZoomImageView(Context context, AttributeSet attrs) {  
  130.         super(context, attrs);  
  131.         currentStatus = STATUS_INIT;  
  132.     }  
  133.   
  134.     /** 
  135.      * 将待展示的图片设置进来。 
  136.      *  
  137.      * @param bitmap 
  138.      *            待展示的Bitmap对象 
  139.      */  
  140.     public void setImageBitmap(Bitmap bitmap) {  
  141.         sourceBitmap = bitmap;  
  142.         invalidate();  
  143.     }  
  144.   
  145.     @Override  
  146.     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  147.         super.onLayout(changed, left, top, right, bottom);  
  148.         if (changed) {  
  149.             // 分别获取到ZoomImageView的宽度和高度  
  150.             width = getWidth();  
  151.             height = getHeight();  
  152.         }  
  153.     }  
  154.   
  155.     @Override  
  156.     public boolean onTouchEvent(MotionEvent event) {  
  157.         switch (event.getActionMasked()) {  
  158.         case MotionEvent.ACTION_POINTER_DOWN:  
  159.             if (event.getPointerCount() == 2) {  
  160.                 // 当有两个手指按在屏幕上时,计算两指之间的距离  
  161.                 lastFingerDis = distanceBetweenFingers(event);  
  162.             }  
  163.             break;  
  164.         case MotionEvent.ACTION_MOVE:  
  165.             if (event.getPointerCount() == 1) {  
  166.                 // 只有单指按在屏幕上移动时,为拖动状态  
  167.                 float xMove = event.getX();  
  168.                 float yMove = event.getY();  
  169.                 if (lastXMove == -1 && lastYMove == -1) {  
  170.                     lastXMove = xMove;  
  171.                     lastYMove = yMove;  
  172.                 }  
  173.                 currentStatus = STATUS_MOVE;  
  174.                 movedDistanceX = xMove - lastXMove;  
  175.                 movedDistanceY = yMove - lastYMove;  
  176.                 // 进行边界检查,不允许将图片拖出边界  
  177.                 if (totalTranslateX + movedDistanceX > 0) {  
  178.                     movedDistanceX = 0;  
  179.                 } else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {  
  180.                     movedDistanceX = 0;  
  181.                 }  
  182.                 if (totalTranslateY + movedDistanceY > 0) {  
  183.                     movedDistanceY = 0;  
  184.                 } else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {  
  185.                     movedDistanceY = 0;  
  186.                 }  
  187.                 // 调用onDraw()方法绘制图片  
  188.                 invalidate();  
  189.                 lastXMove = xMove;  
  190.                 lastYMove = yMove;  
  191.             } else if (event.getPointerCount() == 2) {  
  192.                 // 有两个手指按在屏幕上移动时,为缩放状态  
  193.                 centerPointBetweenFingers(event);  
  194.                 double fingerDis = distanceBetweenFingers(event);  
  195.                 if (fingerDis > lastFingerDis) {  
  196.                     currentStatus = STATUS_ZOOM_OUT;  
  197.                 } else {  
  198.                     currentStatus = STATUS_ZOOM_IN;  
  199.                 }  
  200.                 // 进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例  
  201.                 if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio)  
  202.                         || (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {  
  203.                     scaledRatio = (float) (fingerDis / lastFingerDis);  
  204.                     totalRatio = totalRatio * scaledRatio;  
  205.                     if (totalRatio > 4 * initRatio) {  
  206.                         totalRatio = 4 * initRatio;  
  207.                     } else if (totalRatio < initRatio) {  
  208.                         totalRatio = initRatio;  
  209.                     }  
  210.                     // 调用onDraw()方法绘制图片  
  211.                     invalidate();  
  212.                     lastFingerDis = fingerDis;  
  213.                 }  
  214.             }  
  215.             break;  
  216.         case MotionEvent.ACTION_POINTER_UP:  
  217.             if (event.getPointerCount() == 2) {  
  218.                 // 手指离开屏幕时将临时值还原  
  219.                 lastXMove = -1;  
  220.                 lastYMove = -1;  
  221.             }  
  222.             break;  
  223.         case MotionEvent.ACTION_UP:  
  224.             // 手指离开屏幕时将临时值还原  
  225.             lastXMove = -1;  
  226.             lastYMove = -1;  
  227.             break;  
  228.         default:  
  229.             break;  
  230.         }  
  231.         return true;  
  232.     }  
  233.   
  234.     /** 
  235.      * 根据currentStatus的值来决定对图片进行什么样的绘制操作。 
  236.      */  
  237.     @Override  
  238.     protected void onDraw(Canvas canvas) {  
  239.         super.onDraw(canvas);  
  240.         switch (currentStatus) {  
  241.         case STATUS_ZOOM_OUT:  
  242.         case STATUS_ZOOM_IN:  
  243.             zoom(canvas);  
  244.             break;  
  245.         case STATUS_MOVE:  
  246.             move(canvas);  
  247.             break;  
  248.         case STATUS_INIT:  
  249.             initBitmap(canvas);  
  250.         default:  
  251.             canvas.drawBitmap(sourceBitmap, matrix, null);  
  252.             break;  
  253.         }  
  254.     }  
  255.   
  256.     /** 
  257.      * 对图片进行缩放处理。 
  258.      *  
  259.      * @param canvas 
  260.      */  
  261.     private void zoom(Canvas canvas) {  
  262.         matrix.reset();  
  263.         // 将图片按总缩放比例进行缩放  
  264.         matrix.postScale(totalRatio, totalRatio);  
  265.         float scaledWidth = sourceBitmap.getWidth() * totalRatio;  
  266.         float scaledHeight = sourceBitmap.getHeight() * totalRatio;  
  267.         float translateX = 0f;  
  268.         float translateY = 0f;  
  269.         // 如果当前图片宽度小于屏幕宽度,则按屏幕中心的横坐标进行水平缩放。否则按两指的中心点的横坐标进行水平缩放  
  270.         if (currentBitmapWidth < width) {  
  271.             translateX = (width - scaledWidth) / 2f;  
  272.         } else {  
  273.             translateX = totalTranslateX * scaledRatio + centerPointX * (1 - scaledRatio);  
  274.             // 进行边界检查,保证图片缩放后在水平方向上不会偏移出屏幕  
  275.             if (translateX > 0) {  
  276.                 translateX = 0;  
  277.             } else if (width - translateX > scaledWidth) {  
  278.                 translateX = width - scaledWidth;  
  279.             }  
  280.         }  
  281.         // 如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放  
  282.         if (currentBitmapHeight < height) {  
  283.             translateY = (height - scaledHeight) / 2f;  
  284.         } else {  
  285.             translateY = totalTranslateY * scaledRatio + centerPointY * (1 - scaledRatio);  
  286.             // 进行边界检查,保证图片缩放后在垂直方向上不会偏移出屏幕  
  287.             if (translateY > 0) {  
  288.                 translateY = 0;  
  289.             } else if (height - translateY > scaledHeight) {  
  290.                 translateY = height - scaledHeight;  
  291.             }  
  292.         }  
  293.         // 缩放后对图片进行偏移,以保证缩放后中心点位置不变  
  294.         matrix.postTranslate(translateX, translateY);  
  295.         totalTranslateX = translateX;  
  296.         totalTranslateY = translateY;  
  297.         currentBitmapWidth = scaledWidth;  
  298.         currentBitmapHeight = scaledHeight;  
  299.         canvas.drawBitmap(sourceBitmap, matrix, null);  
  300.     }  
  301.   
  302.     /** 
  303.      * 对图片进行平移处理 
  304.      *  
  305.      * @param canvas 
  306.      */  
  307.     private void move(Canvas canvas) {  
  308.         matrix.reset();  
  309.         // 根据手指移动的距离计算出总偏移值  
  310.         float translateX = totalTranslateX + movedDistanceX;  
  311.         float translateY = totalTranslateY + movedDistanceY;  
  312.         // 先按照已有的缩放比例对图片进行缩放  
  313.         matrix.postScale(totalRatio, totalRatio);  
  314.         // 再根据移动距离进行偏移  
  315.         matrix.postTranslate(translateX, translateY);  
  316.         totalTranslateX = translateX;  
  317.         totalTranslateY = translateY;  
  318.         canvas.drawBitmap(sourceBitmap, matrix, null);  
  319.     }  
  320.   
  321.     /** 
  322.      * 对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。 
  323.      *  
  324.      * @param canvas 
  325.      */  
  326.     private void initBitmap(Canvas canvas) {  
  327.         if (sourceBitmap != null) {  
  328.             matrix.reset();  
  329.             int bitmapWidth = sourceBitmap.getWidth();  
  330.             int bitmapHeight = sourceBitmap.getHeight();  
  331.             if (bitmapWidth > width || bitmapHeight > height) {  
  332.                 if (bitmapWidth - width > bitmapHeight - height) {  
  333.                     // 当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来  
  334.                     float ratio = width / (bitmapWidth * 1.0f);  
  335.                     matrix.postScale(ratio, ratio);  
  336.                     float translateY = (height - (bitmapHeight * ratio)) / 2f;  
  337.                     // 在纵坐标方向上进行偏移,以保证图片居中显示  
  338.                     matrix.postTranslate(0, translateY);  
  339.                     totalTranslateY = translateY;  
  340.                     totalRatio = initRatio = ratio;  
  341.                 } else {  
  342.                     // 当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来  
  343.                     float ratio = height / (bitmapHeight * 1.0f);  
  344.                     matrix.postScale(ratio, ratio);  
  345.                     float translateX = (width - (bitmapWidth * ratio)) / 2f;  
  346.                     // 在横坐标方向上进行偏移,以保证图片居中显示  
  347.                     matrix.postTranslate(translateX, 0);  
  348.                     totalTranslateX = translateX;  
  349.                     totalRatio = initRatio = ratio;  
  350.                 }  
  351.                 currentBitmapWidth = bitmapWidth * initRatio;  
  352.                 currentBitmapHeight = bitmapHeight * initRatio;  
  353.             } else {  
  354.                 // 当图片的宽高都小于屏幕宽高时,直接让图片居中显示  
  355.                 float translateX = (width - sourceBitmap.getWidth()) / 2f;  
  356.                 float translateY = (height - sourceBitmap.getHeight()) / 2f;  
  357.                 matrix.postTranslate(translateX, translateY);  
  358.                 totalTranslateX = translateX;  
  359.                 totalTranslateY = translateY;  
  360.                 totalRatio = initRatio = 1f;  
  361.                 currentBitmapWidth = bitmapWidth;  
  362.                 currentBitmapHeight = bitmapHeight;  
  363.             }  
  364.             canvas.drawBitmap(sourceBitmap, matrix, null);  
  365.         }  
  366.     }  
  367.   
  368.     /** 
  369.      * 计算两个手指之间的距离。 
  370.      *  
  371.      * @param event 
  372.      * @return 两个手指之间的距离 
  373.      */  
  374.     private double distanceBetweenFingers(MotionEvent event) {  
  375.         float disX = Math.abs(event.getX(0) - event.getX(1));  
  376.         float disY = Math.abs(event.getY(0) - event.getY(1));  
  377.         return Math.sqrt(disX * disX + disY * disY);  
  378.     }  
  379.   
  380.     /** 
  381.      * 计算两个手指之间中心点的坐标。 
  382.      *  
  383.      * @param event 
  384.      */  
  385.     private void centerPointBetweenFingers(MotionEvent event) {  
  386.         float xPoint0 = event.getX(0);  
  387.         float yPoint0 = event.getY(0);  
  388.         float xPoint1 = event.getX(1);  
  389.         float yPoint1 = event.getY(1);  
  390.         centerPointX = (xPoint0 + xPoint1) / 2;  
  391.         centerPointY = (yPoint0 + yPoint1) / 2;  
  392.     }  
  393.   
  394. }  

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <com.example.ZoomImageView xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/zoom_image_view"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:background="#000000" >  
  7.   
  8. </com.example.ZoomImageView>  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值