Android自定义控件篇 图片进行平移,缩放,旋转
Posted 彭老希
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自定义控件篇 图片进行平移,缩放,旋转相关的知识,希望对你有一定的参考价值。
一、自定义属性
<declare-styleable name="SingleTouchView">
<attr name="src" format="reference" /> <!-- 用于缩放旋转的图标 -->
<attr name="editable" format="boolean"/> <!-- 是否处于可编辑状态 -->
<attr name="frameColor" format="color" /> <!-- 边框颜色 -->
<attr name="frameWidth" format="dimension" /> <!-- 边框线宽度 -->
<attr name="framePadding" format="dimension" /> <!-- 边框与图片的间距 -->
<attr name="degree" format="float" /> <!-- 旋转角度 -->
<attr name="scale" format="float" /> <!-- 缩放比例 -->
<attr name="controlDrawable" format="reference"/> <!-- 控制图标 -->
<attr name="controlLocation"> <!-- 控制图标的位置 -->
<enum name="left_top" value="0" />
<enum name="right_top" value="1" />
<enum name="right_bottom" value="2" />
<enum name="left_bottom" value="3" />
</attr>
</declare-styleable>
二、自定义控件代码
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
/**
* 单手对图片进行缩放,旋转,平移操作,详情请查看
*/
public class SingleTouchView extends View {
/**
* 图片的最大缩放比例
*/
public static final float MAX_SCALE = 4.0f;
/**
* 图片的最小缩放比例
*/
public static final float MIN_SCALE = 0.3f;
/**
* 控制缩放,旋转图标所在四个点得位置
*/
public static final int LEFT_TOP = 0;
public static final int RIGHT_TOP = 1;
public static final int RIGHT_BOTTOM = 2;
public static final int LEFT_BOTTOM = 3;
/**
* 一些默认的常量
*/
public static final int DEFAULT_FRAME_PADDING = 8;
public static final int DEFAULT_FRAME_WIDTH = 2;
public static final int DEFAULT_FRAME_COLOR = Color.WHITE;
public static final float DEFAULT_SCALE = 1.0f;
public static final float DEFAULT_DEGREE = 0;
public static final int DEFAULT_CONTROL_LOCATION = RIGHT_TOP;
public static final boolean DEFAULT_EDITABLE = true;
public static final int DEFAULT_OTHER_DRAWABLE_WIDTH = 50;
public static final int DEFAULT_OTHER_DRAWABLE_HEIGHT = 50;
/**
* 用于旋转缩放的Bitmap
*/
private Bitmap mBitmap;
/**
* SingleTouchView的中心点坐标,相对于其父类布局而言的
*/
private PointF mCenterPoint = new PointF();
/**
* View的宽度和高度,随着图片的旋转而变化(不包括控制旋转,缩放图片的宽高)
*/
private int mViewWidth, mViewHeight;
/**
* 图片的旋转角度
*/
private float mDegree = DEFAULT_DEGREE;
/**
* 图片的缩放比例
*/
private float mScale = DEFAULT_SCALE;
/**
* 用于缩放,旋转,平移的矩阵
*/
private Matrix matrix = new Matrix();
/**
* SingleTouchView距离父类布局的左间距
*/
private int mViewPaddingLeft;
/**
* SingleTouchView距离父类布局的上间距
*/
private int mViewPaddingTop;
/**
* 图片四个点坐标
*/
private Point mLTPoint;
private Point mRTPoint;
private Point mRBPoint;
private Point mLBPoint;
/**
* 用于缩放,旋转的控制点的坐标
*/
private Point mControlPoint = new Point();
/**
* 用于缩放,旋转的图标
*/
private Drawable controlDrawable;
/**
* 缩放,旋转图标的宽和高
*/
private int mDrawableWidth, mDrawableHeight;
/**
* 画外围框的Path
*/
private Path mPath = new Path();
/**
* 画外围框的画笔
*/
private Paint mPaint ;
/**
* 初始状态
*/
public static final int STATUS_INIT = 0;
/**
* 拖动状态
*/
public static final int STATUS_DRAG = 1;
/**
* 旋转或者放大状态
*/
public static final int STATUS_ROTATE_ZOOM = 2;
/**
* 当前所处的状态
*/
private int mStatus = STATUS_INIT;
/**
* 外边框与图片之间的间距, 单位是dip
*/
private int framePadding = DEFAULT_FRAME_PADDING;
/**
* 外边框颜色
*/
private int frameColor = DEFAULT_FRAME_COLOR;
/**
* 外边框线条粗细, 单位是 dip
*/
private int frameWidth = DEFAULT_FRAME_WIDTH;
/**
* 是否处于可以缩放,平移,旋转状态
*/
private boolean isEditable = DEFAULT_EDITABLE;
private DisplayMetrics metrics;
private PointF mPreMovePointF = new PointF();
private PointF mCurMovePointF = new PointF();
/**
* 图片在旋转时x方向的偏移量
*/
private int offsetX;
/**
* 图片在旋转时y方向的偏移量
*/
private int offsetY;
/**
* 控制图标所在的位置(比如左上,右上,左下,右下)
*/
private int controlLocation = DEFAULT_CONTROL_LOCATION;
public SingleTouchView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SingleTouchView(Context context) {
this(context, null);
}
public SingleTouchView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
obtainStyledAttributes(attrs);
init();
}
/**
* 获取自定义属性
* @param attrs
*/
private void obtainStyledAttributes(AttributeSet attrs){
metrics = getContext().getResources().getDisplayMetrics();
framePadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_FRAME_PADDING, metrics);
frameWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_FRAME_WIDTH, metrics);
TypedArray mTypedArray = getContext().obtainStyledAttributes(attrs,
R.styleable.SingleTouchView);
Drawable srcDrawble = mTypedArray.getDrawable(R.styleable.SingleTouchView_src);
mBitmap = drawable2Bitmap(srcDrawble);
framePadding = mTypedArray.getDimensionPixelSize(R.styleable.SingleTouchView_framePadding, framePadding);
frameWidth = mTypedArray.getDimensionPixelSize(R.styleable.SingleTouchView_frameWidth, frameWidth);
frameColor = mTypedArray.getColor(R.styleable.SingleTouchView_frameColor, DEFAULT_FRAME_COLOR);
mScale = mTypedArray.getFloat(R.styleable.SingleTouchView_scale, DEFAULT_SCALE);
mDegree = mTypedArray.getFloat(R.styleable.SingleTouchView_degree, DEFAULT_DEGREE);
controlDrawable = mTypedArray.getDrawable(R.styleable.SingleTouchView_controlDrawable);
controlLocation = mTypedArray.getInt(R.styleable.SingleTouchView_controlLocation, DEFAULT_CONTROL_LOCATION);
isEditable = mTypedArray.getBoolean(R.styleable.SingleTouchView_editable, DEFAULT_EDITABLE);
mTypedArray.recycle();
}
private void init(){
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(frameColor);
mPaint.setStrokeWidth(frameWidth);
mPaint.setStyle(Style.STROKE);
if(controlDrawable == null){
controlDrawable = getContext().getResources().getDrawable(R.drawable.st_rotate_icon);
}
mDrawableWidth = controlDrawable.getIntrinsicWidth();
mDrawableHeight = controlDrawable.getIntrinsicHeight();
transformDraw();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取SingleTouchView所在父布局的中心点
ViewGroup mViewGroup = (ViewGroup) getParent();
if(null != mViewGroup){
int parentWidth = mViewGroup.getWidth();
int parentHeight = mViewGroup.getHeight();
mCenterPoint.set(parentWidth/2, parentHeight/2);
}
}
/**
* 调整View的大小,位置
*/
private void adjustLayout(){
int actualWidth = mViewWidth + mDrawableWidth;
int actualHeight = mViewHeight + mDrawableHeight;
int newPaddingLeft = (int) (mCenterPoint.x - actualWidth /2);
int newPaddingTop = (int) (mCenterPoint.y - actualHeight/2);
if(mViewPaddingLeft != newPaddingLeft || mViewPaddingTop != newPaddingTop){
mViewPaddingLeft = newPaddingLeft;
mViewPaddingTop = newPaddingTop;
// layout(newPaddingLeft, newPaddingTop, newPaddingLeft + actualWidth, newPaddingTop + actualHeight);
}
layout(newPaddingLeft, newPaddingTop, newPaddingLeft + actualWidth, newPaddingTop + actualHeight);
}
/**
* 设置旋转图
* @param bitmap
*/
public void setImageBitamp(Bitmap bitmap){
this.mBitmap = bitmap;
transformDraw();
}
/**
* 设置旋转图
* @param drawable
*/
public void setImageDrawable(Drawable drawable){
this.mBitmap = drawable2Bitmap(drawable);
transformDraw();
}
/**
* 从Drawable中获取Bitmap对象
* @param drawable
* @return
*/
private Bitmap drawable2Bitmap(Drawable drawable) {
try {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
int intrinsicWidth = drawable.getIntrinsicWidth();
int intrinsicHeight = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(
intrinsicWidth <= 0 ? DEFAULT_OTHER_DRAWABLE_WIDTH
: intrinsicWidth,
intrinsicHeight <= 0 ? DEFAULT_OTHER_DRAWABLE_HEIGHT
: intrinsicHeight, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (OutOfMemoryError e) {
return null;
}
}
/**
* 根据id设置旋转图
* @param resId
*/
public void setImageResource(int resId){
Drawable drawable = getContext().getResources().getDrawable(resId);
setImageDrawable(drawable);
}
@Override
protected void onDraw(Canvas canvas) {
//每次draw之前调整View的位置和大小
super.onDraw(canvas);
if(mBitmap == null) return;
canvas.drawBitmap(mBitmap, matrix, mPaint);
//处于可编辑状态才画边框和控制图标
if(isEditable){
mPath.reset();
mPath.moveTo(mLTPoint.x, mLTPoint.y);
mPath.lineTo(mRTPoint.x, mRTPoint.y);
mPath.lineTo(mRBPoint.x, mRBPoint.y);
mPath.lineTo(mLBPoint.x, mLBPoint.y);
mPath.lineTo(mLTPoint.x, mLTPoint.y);
mPath.lineTo(mRTPoint.x, mRTPoint.y);
canvas.drawPath(mPath, mPaint);
//画旋转, 缩放图标
controlDrawable.setBounds(mControlPoint.x - mDrawableWidth / 2,
mControlPoint.y - mDrawableHeight / 2, mControlPoint.x + mDrawableWidth
/ 2, mControlPoint.y + mDrawableHeight / 2);
controlDrawable.draw(canvas);
}
adjustLayout();
}
/**
* 设置Matrix, 强制刷新
*/
private void transformDraw(){
if(mBitmap == null) return;
int bitmapWidth = (int)(mBitmap.getWidth() * mScale);
int bitmapHeight = (int)(mBitmap.getHeight()* mScale);
computeRect(-framePadding, -framePadding, bitmapWidth + framePadding, bitmapHeight + framePadding, mDegree);
//设置缩放比例
matrix.setScale(mScale, mScale);
//绕着图片中心进行旋转
matrix.postRotate(mDegree % 360, bitmapWidth/2, bitmapHeight/2);
//设置画该图片的起始点
matrix.postTranslate(offsetX + mDrawableWidth/2, offsetY + mDrawableHeight/2);
adjustLayout();
}
public boolean onTouchEvent(MotionEvent event) {
if(!isEditable){
return super.onTouchEvent(event);
}
switch (event.getAction() ) {
case MotionEvent.ACTION_DOWN:
mPreMovePointF.set(event.getX() + mViewPaddingLeft, event.getY() + mViewPaddingTop);
mStatus = JudgeStatus(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
mStatus = STATUS_INIT;
break;
case MotionEvent.ACTION_MOVE:
mCurMovePointF.set(event.getX() + mViewPaddingLeft, event.getY() + mViewPaddingTop);
if (mStatus == STATUS_ROTATE_ZOOM) {
float scale = 1f;
int halfBitmapWidth = mBitmap.以上是关于Android自定义控件篇 图片进行平移,缩放,旋转的主要内容,如果未能解决你的问题,请参考以下文章
Android Matrix手势缩放自定义view 不止于Imageview