热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

1.阻尼效果listviewpublicclassMyListViewextendsListViewimplementsRunnable{private


1.阻尼效果listview

public class MyListView extends ListView implements Runnable {
	
	private float mLastDownY = 0f; 
    private int mDistance = 0; 
    private int mStep = 10; 
    private boolean mPositive = false; 
 

    public MyListView (Context context, AttributeSet attrs) { 
          super(context, attrs); 
    } 
 
    public MyListView (Context context, AttributeSet attrs, int defStyle) { 
          super(context, attrs, defStyle); 
    } 
 
    public MyListView (Context context) { 
          super(context); 
    } 
 
    
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
         switch (event.getAction()) { 
              case MotionEvent.ACTION_DOWN: 
                   if (mLastDownY == 0f && mDistance == 0) { 
                         mLastDownY = event.getY(); 
                   return true; 
              } 
              break; 
		 
		      case MotionEvent.ACTION_CANCEL: 
		           break;
		
		      case MotionEvent.ACTION_UP: 
		          if (mDistance != 0) { 
		           mStep = 1; 
		           mPositive = (mDistance >= 0); 
		           this.post(this); 
		           return true; 
		        } 
		         mLastDownY = 0f; 
		         mDistance = 0; 
		         break; 
		 
		      case MotionEvent.ACTION_MOVE: 
		         if (mLastDownY != 0f) { 
		              mDistance = (int) (mLastDownY - event.getY()); 
		              if ((mDistance <0 && getFirstVisiblePosition() == 0 && getChildAt(0).getTop() == 0) || (mDistance > 0 && getLastVisiblePosition() == getCount() - 1)) { 
		                   mDistance /= 2; 
		                   scrollTo(0, mDistance); 
		                   return true; 
		               } 
		        } 
        mDistance = 0; 
        break; 
        } 
        return super.onTouchEvent(event); 
    } 
 
    public void run() { 
          mDistance += mDistance > 0 ? -mStep : mStep; 
          scrollTo(0, mDistance); 
          if ((mPositive && mDistance <= 0) || (!mPositive && mDistance >= 0)) { 
                scrollTo(0, 0); 
                mDistance = 0; 
                mLastDownY = 0f; 
                return; 
           } 
          mStep += 1; 
          this.postDelayed(this, 10); 
     } 
} 

2.阻尼效果 scrollview

public class CustomScrollView extends ScrollView {

	private View inner;// 孩子View

	private float y;// 点击时y坐标

	private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)

	private boolean isCount = false;// 是否开始计算

	private boolean isMoveing = false;// 是否开始移动.

	private ImageView imageView;

	private int initTop, initbottom;// 初始高度
	private int top, bottom;// 拖动时时高度。

	public void setImageView(ImageView imageView) {
		this.imageView = imageView;
	}

	public CustomScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	/***
	 * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate
	 * 方法,也应该调用父类的方法,使该方法得以执行.
	 */
	@Override
	protected void onFinishInflate() {
		if (getChildCount() > 0) {
			inner = getChildAt(0);
		}
	}

	/** touch 事件处理 **/
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (inner != null) {
			commOnTouchEvent(ev);
		}
		return super.onTouchEvent(ev);
	}

	/***
	 * 触摸事件
	 * 
	 * @param ev
	 */
	public void commOnTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			top = initTop = imageView.getTop();
			bottom = initbottom = imageView.getBottom();
			break;

		case MotionEvent.ACTION_UP:

			isMoveing = false;
			// 手指松开.
			if (isNeedAnimation()) {

				animation();

			}
			break;
		/***
		 * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到,
		 * 因为此时是MyScrollView的touch事件传递到到了LIstView的孩子item上面.所以从第二次计算开始.
		 * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行.
		 */
		case MotionEvent.ACTION_MOVE:

			final float preY = y;// 按下时的y坐标

			float nowY = ev.getY();// 时时y坐标
			int deltaY = (int) (nowY - preY);// 滑动距离
			if (!isCount) {
				deltaY = 0; // 在这里要归0.
			}

			if (deltaY <0 && top <= initTop)
				return;

			// 当滚动到最上或者最下时就不会再滚动,这时移动布局
			isNeedMove();

			if (isMoveing) {
				// 初始化头部矩形
				if (normal.isEmpty()) {
					// 保存正常的布局位置
					normal.set(inner.getLeft(), inner.getTop(),
							inner.getRight(), inner.getBottom());
				}

				// 移动布局
				inner.layout(inner.getLeft(), inner.getTop() + deltaY / 3,
						inner.getRight(), inner.getBottom() + deltaY / 3);

				top += (deltaY / 6);
				bottom += (deltaY / 6);
				imageView.layout(imageView.getLeft(), top,
						imageView.getRight(), bottom);
			}

			isCount = true;
			y = nowY;
			break;

		default:
			break;

		}
	}

	/***
	 * 回缩动画
	 */
	public void animation() {

		TranslateAnimation taa = new TranslateAnimation(0, 0, top + 200,
				initTop + 200);
		taa.setDuration(200);
		imageView.startAnimation(taa);
		imageView.layout(imageView.getLeft(), initTop, imageView.getRight(),
				initbottom);

		// 开启移动动画
		TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),
				normal.top);
		ta.setDuration(200);
		inner.startAnimation(ta);
		// 设置回到正常的布局位置
		inner.layout(normal.left, normal.top, normal.right, normal.bottom);
		normal.setEmpty();

		isCount = false;
		y = 0;// 手指松开要归0.

	}

	// 是否需要开启动画
	public boolean isNeedAnimation() {
		return !normal.isEmpty();
	}

	/***
	 * 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度
	 * 
	 * getHeight():获取的是屏幕的高度
	 * 
	 * @return
	 */
	public void isNeedMove() {
		int offset = inner.getMeasuredHeight() - getHeight();
		int scrollY = getScrollY();
		// Log.e("jj", "scrolly=" + scrollY);
		// 0是顶部,后面那个是底部
		if (scrollY == 0 || scrollY == offset) {
			isMoveing = true;
		}
	}

}


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

public class RoundedImageView extends ImageView {

	public RoundedImageView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	public RoundedImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	@Override
	protected void onDraw(Canvas canvas) {

		Drawable drawable = getDrawable();

		if (drawable == null) {
			return;
		}

		if (getWidth() == 0 || getHeight() == 0) {
			return;
		}
		Bitmap b = ((BitmapDrawable) drawable).getBitmap();
		Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

		int w = getWidth(), h = getHeight();

		Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
		canvas.drawBitmap(roundBitmap, 0, 0, null);

	}

	
	public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
		Bitmap sbmp;
		if (bmp.getWidth() != radius || bmp.getHeight() != radius)
			sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
		else
			sbmp = bmp;
		Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),
				Config.ARGB_8888);
		Canvas canvas = new Canvas(output);

		final int color = 0xffa19774;
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());

		paint.setAntiAlias(true);
		paint.setFilterBitmap(true);
		paint.setDither(true);
		canvas.drawARGB(0, 0, 0, 0);
		paint.setColor(Color.parseColor("#BAB399"));
		canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f,
				sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);
		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(sbmp, rect, rect, paint);

		return output;
	}

}
比如 设置 imageview的 w,h

 


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


public class SlidButton extends View implements OnTouchListener {  
  
    private boolean nowChoose = false;// 记录当前按钮是否打开,true为打开,false为关闭  
    private boolean OnSlip= false;// 记录用户是否在滑动  
    private float   downX, nowX; // 按下时的x,当前的x  
    private Rect    btn_on, btn_off;// 打开和关闭状态下,游标的Rect  
  
    private boolean isChgLsnOn = false;//是否设置监听  
    private OnChangedListener changedLis;  
    
    int begin,end;//控件当前的位置
    private Bitmap bg_on, bg_off, slip_btn;  
  
    public SlidButton(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        init();  
    }  
  
    public SlidButton(Context context) {  
        super(context);  
        init();  
    }  
  
      
    private void init() {  
        // 载入图片资源  
        bg_on = BitmapFactory.decodeResource(getResources(),  
                R.drawable.sild_bg_on1);  
        bg_off = BitmapFactory.decodeResource(getResources(),  
                R.drawable.sild_bg_off1);  
        slip_btn = BitmapFactory.decodeResource(getResources(),  
                R.drawable.sild_bg_btn1);  
        
        
        // 获得需要的Rect数据  
        btn_on = new Rect(0, 0, slip_btn.getWidth() , slip_btn.getHeight());  
        btn_off = new Rect(bg_off.getWidth() - slip_btn.getWidth(), 0,  
                bg_off.getWidth(), slip_btn.getHeight());  
        setOnTouchListener(this);  
    }  
    
    
    
    @Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        Matrix matrix = new Matrix(); 
        begin			=this.getWidth() - bg_off.getWidth();
        end				=9;
        matrix.postTranslate(begin, end);
        Paint paint = new Paint();  
        float x;  
          
        {  
//            if (nowX<(bg_on.getWidth()/2)) //滑动到前半段与后半段的背景不同,在此做判断  
        	if(!nowChoose){
        		
        		 canvas.drawBitmap(bg_off, matrix, paint);//画出关闭时的背景  
        	}else{
        		 canvas.drawBitmap(bg_on, matrix, paint);//画出打开时的背景   
        	}  
               
                  
            if (onSlip) {//是否是在滑动状态,    
                if(nowX >= bg_on.getWidth()){
                	//是否划出指定范围,不能让游标跑到外头,必须做这个判断  
                   x = bg_on.getWidth() - slip_btn.getWidth()/2;//减去游标1/2的长度  
                
                }else{
                   x = nowX - slip_btn.getWidth() / 2;  	
                }  
                   
           
            }else {  
                if(nowChoose)//根据现在的开关状态设置画游标的位置   
                    x = btn_off.left;  
                else  
                    x = btn_on.left;  
            }  
              
            if (x <0 ) //对游标位置进行异常判断..  
                x = 0;  
            else if(x > bg_on.getWidth() - slip_btn.getWidth())  
                x = bg_on.getWidth() - slip_btn.getWidth();  
              
            canvas.drawBitmap(slip_btn, x + begin, end, paint);//画出游标.     
        }  
    }  
  
    
    
    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
          
        switch (event.getAction()) {//根据动作来执行代码  
              
            case MotionEvent.ACTION_MOVE:
                nowX = event.getX();  
                break;  
           
            case MotionEvent.ACTION_DOWN:  
                if (event.getX() = begin+(bg_on.getWidth()/2))   
                    nowChoose = true;  
                else   
                    nowChoose = false; */ 
                nowChoose		=!nowChoose;
                if(isChgLsnOn && (lastChoose != nowChoose))//如果设置了监听器,就调用其方法.  
                    changedLis.OnChanged(nowChoose);  
                break;  
            default:  
                break;  
        }  
        invalidate();  
        return true;  
    }  
  
      
    public void SetOnChangedListener(OnChangedListener l){//设置监听器,当状态修改的时候  
        isChgLsnOn = true;  
        changedLis = l;  
    }  
      
    public interface OnChangedListener {  
        abstract void OnChanged(boolean checkState);  
    }  
}

             

4. 缩小放大图片


public class TouchImageView extends ImageView {

    Matrix matrix;

    // We can be in one of these 3 states
    static final int NOnE= 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    int mode = NONE;

    // Remember some things for zooming
    PointF last = new PointF();
    PointF start = new PointF();
    float minScale = 1f;
    float maxScale = 3f;
    float[] m;


    int viewWidth, viewHeight;
    static final int CLICK = 3;
    float saveScale = 1f;
    protected float origWidth, origHeight;
    int oldMeasuredWidth, oldMeasuredHeight;


    ScaleGestureDetector mScaleDetector;

    Context context;

    public TouchImageView(Context context) {
        super(context);
        sharedConstructing(context);
    }

    public TouchImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        sharedConstructing(context);
    }
    
    private void sharedConstructing(Context context) {
        super.setClickable(true);
        this.cOntext= context;
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        matrix = new Matrix();
        m = new float[9];
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);

        setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                mScaleDetector.onTouchEvent(event);
                PointF curr = new PointF(event.getX(), event.getY());

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                    	last.set(curr);
                        start.set(last);
                        mode = DRAG;
                        break;
                        
                    case MotionEvent.ACTION_MOVE:
                        if (mode == DRAG) {
                            float deltaX = curr.x - last.x;
                            float deltaY = curr.y - last.y;
                            float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);
                            float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);
                            matrix.postTranslate(fixTransX, fixTransY);
                            fixTrans();
                            last.set(curr.x, curr.y);
                        }
                        break;

                    case MotionEvent.ACTION_UP:
                        mode = NONE;
                        int xDiff = (int) Math.abs(curr.x - start.x);
                        int yDiff = (int) Math.abs(curr.y - start.y);
                        if (xDiff  maxScale) {
                saveScale = maxScale;
                mScaleFactor = maxScale / origScale;
            } else if (saveScale  maxTrans)
            return -trans + maxTrans;
        return 0;
    }
    
    float getFixDragTrans(float delta, float viewSize, float contentSize) {
        if (contentSize <= viewSize) {
            return 0;
        }
        return delta;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        viewHeight = MeasureSpec.getSize(heightMeasureSpec);
        
        //
        // Rescales image on rotation
        //
        if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
                || viewWidth == 0 || viewHeight == 0)
            return;
        oldMeasuredHeight = viewHeight;
        oldMeasuredWidth = viewWidth;

        if (saveScale == 1) {
            //Fit to screen.
            float scale;

            Drawable drawable = getDrawable();
            if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0)
                return;
            int bmWidth = drawable.getIntrinsicWidth();
            int bmHeight = drawable.getIntrinsicHeight();
            
            Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);

            float scaleX = (float) viewWidth / (float) bmWidth;
            float scaleY = (float) viewHeight / (float) bmHeight;
            scale = Math.min(scaleX, scaleY);
            matrix.setScale(scale, scale);

            // Center the image
            float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
            float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
            redundantYSpace /= (float) 2;
            redundantXSpace /= (float) 2;

            matrix.postTranslate(redundantXSpace, redundantYSpace);

            origWidth = viewWidth - 2 * redundantXSpace;
            origHeight = viewHeight - 2 * redundantYSpace;
            setImageMatrix(matrix);
        }
        fixTrans();
    }
}



public class TouchImageViewActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TouchImageView img = (TouchImageView) findViewById(R.id.snoop);
        img.setImageResource(R.drawable.snoopy);
        img.setMaxZoom(4f);
    }
}

/**
 * 自定义的ImageView控制,可对图片进行多点触控缩放和拖动
 * 
 * @author guolin
 */
public class ZoomImageView extends View {

	/**
	 * 初始化状态常量
	 */
	public static final int STATUS_INIT = 1;

	/**
	 * 图片放大状态常量
	 */
	public static final int STATUS_ZOOM_OUT = 2;

	/**
	 * 图片缩小状态常量
	 */
	public static final int STATUS_ZOOM_IN = 3;

	/**
	 * 图片拖动状态常量
	 */
	public static final int STATUS_MOVE = 4;

	/**
	 * 用于对图片进行移动和缩放变换的矩阵
	 */
	private Matrix matrix = new Matrix();

	/**
	 * 待展示的Bitmap对象
	 */
	private Bitmap sourceBitmap;

	/**
	 * 记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE
	 */
	private int currentStatus;

	/**
	 * ZoomImageView控件的宽度
	 */
	private int width;

	/**
	 * ZoomImageView控件的高度
	 */
	private int height;

	/**
	 * 记录两指同时放在屏幕上时,中心点的横坐标值
	 */
	private float centerPointX;

	/**
	 * 记录两指同时放在屏幕上时,中心点的纵坐标值
	 */
	private float centerPointY;

	/**
	 * 记录当前图片的宽度,图片被缩放时,这个值会一起变动
	 */
	private float currentBitmapWidth;

	/**
	 * 记录当前图片的高度,图片被缩放时,这个值会一起变动
	 */
	private float currentBitmapHeight;

	/**
	 * 记录上次手指移动时的横坐标
	 */
	private float lastXMove = -1;

	/**
	 * 记录上次手指移动时的纵坐标
	 */
	private float lastYMove = -1;

	/**
	 * 记录手指在横坐标方向上的移动距离
	 */
	private float movedDistanceX;

	/**
	 * 记录手指在纵坐标方向上的移动距离
	 */
	private float movedDistanceY;

	/**
	 * 记录图片在矩阵上的横向偏移值
	 */
	private float totalTranslateX;

	/**
	 * 记录图片在矩阵上的纵向偏移值
	 */
	private float totalTranslateY;

	/**
	 * 记录图片在矩阵上的总缩放比例
	 */
	private float totalRatio;

	/**
	 * 记录手指移动的距离所造成的缩放比例
	 */
	private float scaledRatio;

	/**
	 * 记录图片初始化时的缩放比例
	 */
	private float initRatio;

	/**
	 * 记录上次两指之间的距离
	 */
	private double lastFingerDis;

	/**
	 * ZoomImageView构造函数,将当前操作状态设为STATUS_INIT。
	 * 
	 * @param context
	 * @param attrs
	 */
	public ZoomImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		currentStatus = STATUS_INIT;
	}

	/**
	 * 将待展示的图片设置进来。
	 * 
	 * @param bitmap
	 *            待展示的Bitmap对象
	 */
	public void setImageBitmap(Bitmap bitmap) {
		sourceBitmap = bitmap;
		invalidate();
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		if (changed) {
			// 分别获取到ZoomImageView的宽度和高度
			width = getWidth();
			height = getHeight();
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getActionMasked()) {
		case MotionEvent.ACTION_POINTER_DOWN:
			if (event.getPointerCount() == 2) {
				// 当有两个手指按在屏幕上时,计算两指之间的距离
				lastFingerDis = distanceBetweenFingers(event);
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (event.getPointerCount() == 1) {
				// 只有单指按在屏幕上移动时,为拖动状态
				float xMove = event.getX();
				float yMove = event.getY();
				if (lastXMove == -1 && lastYMove == -1) {
					lastXMove = xMove;
					lastYMove = yMove;
				}
				currentStatus = STATUS_MOVE;
				movedDistanceX = xMove - lastXMove;
				movedDistanceY = yMove - lastYMove;
				// 进行边界检查,不允许将图片拖出边界
				if (totalTranslateX + movedDistanceX > 0) {
					movedDistanceX = 0;
				} else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {
					movedDistanceX = 0;
				}
				if (totalTranslateY + movedDistanceY > 0) {
					movedDistanceY = 0;
				} else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {
					movedDistanceY = 0;
				}
				// 调用onDraw()方法绘制图片
				invalidate();
				lastXMove = xMove;
				lastYMove = yMove;
			} else if (event.getPointerCount() == 2) {
				// 有两个手指按在屏幕上移动时,为缩放状态
				centerPointBetweenFingers(event);
				double fingerDis = distanceBetweenFingers(event);
				if (fingerDis > lastFingerDis) {
					currentStatus = STATUS_ZOOM_OUT;
				} else {
					currentStatus = STATUS_ZOOM_IN;
				}
				// 进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例
				if ((currentStatus == STATUS_ZOOM_OUT && totalRatio <4 * initRatio)
						|| (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {
					scaledRatio = (float) (fingerDis / lastFingerDis);
					totalRatio = totalRatio * scaledRatio;
					if (totalRatio > 4 * initRatio) {
						totalRatio = 4 * initRatio;
					} else if (totalRatio  0) {
				translateX = 0;
			} else if (width - translateX > scaledWidth) {
				translateX = width - scaledWidth;
			}
		}
		// 如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放
		if (currentBitmapHeight  0) {
				translateY = 0;
			} else if (height - translateY > scaledHeight) {
				translateY = height - scaledHeight;
			}
		}
		// 缩放后对图片进行偏移,以保证缩放后中心点位置不变
		matrix.postTranslate(translateX, translateY);
		totalTranslateX = translateX;
		totalTranslateY = translateY;
		currentBitmapWidth = scaledWidth;
		currentBitmapHeight = scaledHeight;
		canvas.drawBitmap(sourceBitmap, matrix, null);
	}

	/**
	 * 对图片进行平移处理
	 * 
	 * @param canvas
	 */
	private void move(Canvas canvas) {
		matrix.reset();
		// 根据手指移动的距离计算出总偏移值
		float translateX = totalTranslateX + movedDistanceX;
		float translateY = totalTranslateY + movedDistanceY;
		// 先按照已有的缩放比例对图片进行缩放
		matrix.postScale(totalRatio, totalRatio);
		// 再根据移动距离进行偏移
		matrix.postTranslate(translateX, translateY);
		totalTranslateX = translateX;
		totalTranslateY = translateY;
		canvas.drawBitmap(sourceBitmap, matrix, null);
	}

	/**
	 * 对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。
	 * 
	 * @param canvas
	 */
	private void initBitmap(Canvas canvas) {
		if (sourceBitmap != null) {
			matrix.reset();
			int bitmapWidth = sourceBitmap.getWidth();
			int bitmapHeight = sourceBitmap.getHeight();
			if (bitmapWidth > width || bitmapHeight > height) {
				if (bitmapWidth - width > bitmapHeight - height) {
					// 当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来
					float ratio = width / (bitmapWidth * 1.0f);
					matrix.postScale(ratio, ratio);
					float translateY = (height - (bitmapHeight * ratio)) / 2f;
					// 在纵坐标方向上进行偏移,以保证图片居中显示
					matrix.postTranslate(0, translateY);
					totalTranslateY = translateY;
					totalRatio = initRatio = ratio;
				} else {
					// 当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来
					float ratio = height / (bitmapHeight * 1.0f);
					matrix.postScale(ratio, ratio);
					float translateX = (width - (bitmapWidth * ratio)) / 2f;
					// 在横坐标方向上进行偏移,以保证图片居中显示
					matrix.postTranslate(translateX, 0);
					totalTranslateX = translateX;
					totalRatio = initRatio = ratio;
				}
				currentBitmapWidth = bitmapWidth * initRatio;
				currentBitmapHeight = bitmapHeight * initRatio;
			} else {
				// 当图片的宽高都小于屏幕宽高时,直接让图片居中显示
				float translateX = (width - sourceBitmap.getWidth()) / 2f;
				float translateY = (height - sourceBitmap.getHeight()) / 2f;
				matrix.postTranslate(translateX, translateY);
				totalTranslateX = translateX;
				totalTranslateY = translateY;
				totalRatio = initRatio = 1f;
				currentBitmapWidth = bitmapWidth;
				currentBitmapHeight = bitmapHeight;
			}
			canvas.drawBitmap(sourceBitmap, matrix, null);
		}
	}

	/**
	 * 计算两个手指之间的距离。
	 * 
	 * @param event
	 * @return 两个手指之间的距离
	 */
	private double distanceBetweenFingers(MotionEvent event) {
		float disX = Math.abs(event.getX(0) - event.getX(1));
		float disY = Math.abs(event.getY(0) - event.getY(1));
		return Math.sqrt(disX * disX + disY * disY);
	}

	/**
	 * 计算两个手指之间中心点的坐标。
	 * 
	 * @param event
	 */
	private void centerPointBetweenFingers(MotionEvent event) {
		float xPoint0 = event.getX(0);
		float yPoint0 = event.getY(0);
		float xPoint1 = event.getX(1);
		float yPoint1 = event.getY(1);
		centerPointX = (xPoint0 + xPoint1) / 2;
		centerPointY = (yPoint0 + yPoint1) / 2;
	}

}









推荐阅读
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • 在Android开发中,实现多点触控功能需要使用`OnTouchListener`监听器来捕获触摸事件,并在`onTouch`方法中进行详细的事件处理。为了优化多点触控的交互体验,开发者可以通过识别不同的触摸手势(如缩放、旋转等)并进行相应的逻辑处理。此外,还可以结合`MotionEvent`类提供的方法,如`getPointerCount()`和`getPointerId()`,来精确控制每个触点的行为,从而提升用户操作的流畅性和响应性。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • 在本文中,我们将详细介绍如何构建一个用于自动回复消息的XML类。当微信服务器接收到用户消息时,该类将生成相应的自动回复消息。以下是具体的代码实现:```phpclass We_Xml { // 代码内容}```通过这个类,开发者可以轻松地处理各种消息类型,并实现高效的自动回复功能。我们将深入探讨类的各个方法和属性,帮助读者更好地理解和应用这一技术。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • 本指南介绍了 `requests` 库的基本使用方法,详细解释了其七个主要函数。其中,`requests.request()` 是构建请求的基础方法,支持其他高级功能的实现。此外,我们还重点介绍了如何使用 `requests.get()` 方法来获取 HTML 网页内容,这是进行网页数据抓取和解析的重要步骤。通过这些基础方法,读者可以轻松上手并掌握网页数据抓取的核心技巧。 ... [详细]
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
  • 本文详细探讨了 jQuery 中 `ajaxSubmit` 方法的使用技巧及其应用场景。首先,介绍了如何正确引入必要的脚本文件,如 `jquery.form.js` 和 `jquery-1.8.0.min.js`。接着,通过具体示例展示了如何利用 `ajaxSubmit` 方法实现表单的异步提交,包括数据的发送、接收和处理。此外,还讨论了该方法在不同场景下的应用,如文件上传、表单验证和动态更新页面内容等,提供了丰富的代码示例和最佳实践建议。 ... [详细]
  • 本文深入探讨了Ajax的工作机制及其在现代Web开发中的应用。Ajax作为一种异步通信技术,改变了传统的客户端与服务器直接交互的模式。通过引入Ajax,客户端与服务器之间的通信变得更加高效和灵活。文章详细分析了Ajax的核心原理,包括XMLHttpRequest对象的使用、数据传输格式(如JSON和XML)以及事件处理机制。此外,还介绍了Ajax在提升用户体验、实现动态页面更新等方面的具体应用,并讨论了其在当前Web开发中的重要性和未来发展趋势。 ... [详细]
author-avatar
山人
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有