C#生成word記載實例解析。本站提示廣大學習愛好者:(C#生成word記載實例解析)文章只能為提供參考,不一定能成為您想要的結果。以下是C#生成word記載實例解析正文
信任年夜家應用多點對圖片停止縮放,平移的操作很熟習了,年夜部門年夜圖的閱讀都具有此功效,有些app還可以對圖片停止扭轉操作,QQ的年夜圖閱讀便可以對圖片停止扭轉操作,年夜家都曉得對圖片停止縮放,平移,扭轉等操作可使用Matrix來完成,Matrix就是一個3X3的矩陣,對圖片的處置可分為四個基本變換操作,Translate(平移變換)、Rotate(扭轉變換)、Scale (縮放變換)、Skew(錯切變換),假如年夜家對Matrix不太懂得的話可以看看這篇文章(點擊檢查),作者對每種Matrix的變換寫的很清晰,然則假如應用一個手指對圖片停止縮放,平移,扭轉等操作年夜家能否懂得呢,其實單手指操作跟多手指操作差不多,固然也是應用Matrix來完成的,不過是在縮放比例和扭轉角度的盤算下面有些紛歧樣,或許你會有疑問,多點操作圖片縮放扭轉是兩個手指操作,平移的時刻是一個手指操作,那末你單手在圖片即平移,又縮放扭轉豈非不會有抵觸嗎?是的,如許子確定是不可的,我們必需將平移和縮放扭轉停止離開。以下圖

圖片裡面的框是一個邊框,假如我們手指觸摸的是下面的藍色小圖標我們就對其停止縮放扭轉操作,假如是觸摸到其他的區域我們就對其停止平移操作,如許就防止了下面所說的抵觸成績,這裡對圖片的平移操作並沒有應用Matrix來完成,而是應用layout()辦法來對其停止地位的變換。

盤算縮放比例比擬簡略,應用手指挪動的點到圖片地點中間點的間隔除以圖片對角線的一半就是縮放比例了,接上去就盤算扭轉角度,以下圖

preMove是手指挪動前一個點,curMove就是以後手指地點的點,還有一個中間點center,曉得三個點求扭轉的夾角是否是很簡略呢,就是線段a和線段c的一個夾角,假定夾角為o, o的余弦值 cos o = (a * a + c * c - b * b) / (2 * a * c), 曉得余弦值夾角就出來了,然則這裡還有一個成績,我們在應用Matrix對圖片停止扭轉的時刻須要差別順時針扭轉照樣逆時針扭轉,順時針扭轉角度為正,所以下面我們只求出了扭轉的角度,其實不曉得是順時針照樣逆時針。
詳細怎樣求是順時針角度照樣逆時針角度呢?有些同窗能夠會依據curMove和ProMove的x ,y 的年夜小來斷定,好比下面的圖中,假如curMove.x > proMove.x則為順時針,不然為逆時針,這固然是一種方法,可是你想過這類辦法只合適在第二象限,在第一,第三,第四象限如許子斷定就不可了,固然你可以斷定以後的點在第幾象限,然後在分歧的象限采取分歧的斷定,如許子斷定起來會很龐雜。
有無加倍簡略的辦法來斷定呢?謎底是確定的,我們可使用數學中的向量叉乘來斷定。假設向量A(x1, y1)和向量B(x2, y2),我們可使用向量叉乘 |A X B| = x1*y2 - x2*y1 = |A|×|B|×sin(向量A到B的夾角), 所以這個值的正負也就是A到B扭轉角sin值的正負, 順時針扭轉角度0~180,sin>0, 順時針扭轉角度180~360或許說逆時針扭轉0~180,sin<0, 所以我們可以用個center到proMove的向量 叉乘 center到curMove的向量來斷定是順時針扭轉照樣逆時針扭轉。
接上去我們就開端著手完成此功效,我們采取一個自界說的View來完成,這裡就叫SingleTouchView,直接繼續View, 從下面的圖中我們可以界說出一些自界說的屬性,好比用於縮放的圖片,掌握縮放扭轉的小圖標,圖片邊框的色彩等,我界說了以下的屬性
<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>
接上去就是自界說SingleTouchView的代碼,代碼有點長,正文照樣蠻具體的
package com.example.singletouchview;
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;
/**
* 單手對圖片停止縮放,扭轉,平移操作,概況請檢查
*
* @blog http://blog.csdn.net/xiaanming/article/details/42833893
*
* @author xiaanming
*
*/
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.getWidth() / 2;
int halfBitmapHeight = mBitmap.getHeight() /2 ;
//圖片某個點到圖片中間的間隔
float bitmapToCenterDistance = FloatMath.sqrt(halfBitmapWidth * halfBitmapWidth + halfBitmapHeight * halfBitmapHeight);
//挪動的點到圖片中間的間隔
float moveToCenterDistance = distance4PointF(mCenterPoint, mCurMovePointF);
//盤算縮放比例
scale = moveToCenterDistance / bitmapToCenterDistance;
//縮放比例的界線斷定
if (scale <= MIN_SCALE) {
scale = MIN_SCALE;
} else if (scale >= MAX_SCALE) {
scale = MAX_SCALE;
}
// 角度
double a = distance4PointF(mCenterPoint, mPreMovePointF);
double b = distance4PointF(mPreMovePointF, mCurMovePointF);
double c = distance4PointF(mCenterPoint, mCurMovePointF);
double cosb = (a * a + c * c - b * b) / (2 * a * c);
if (cosb >= 1) {
cosb = 1f;
}
double radian = Math.acos(cosb);
float newDegree = (float) radianToDegree(radian);
//center -> proMove的向量, 我們應用PointF來完成
PointF centerToProMove = new PointF((mPreMovePointF.x - mCenterPoint.x), (mPreMovePointF.y - mCenterPoint.y));
//center -> curMove 的向量
PointF centerToCurMove = new PointF((mCurMovePointF.x - mCenterPoint.x), (mCurMovePointF.y - mCenterPoint.y));
//向量叉乘成果, 假如成果為正數, 表現為逆時針, 成果為負數表現順時針
float result = centerToProMove.x * centerToCurMove.y - centerToProMove.y * centerToCurMove.x;
if (result < 0) {
newDegree = -newDegree;
}
mDegree = mDegree + newDegree;
mScale = scale;
transformDraw();
}
else if (mStatus == STATUS_DRAG) {
// 修正中間點
mCenterPoint.x += mCurMovePointF.x - mPreMovePointF.x;
mCenterPoint.y += mCurMovePointF.y - mPreMovePointF.y;
System.out.println(this + "move = " + mCenterPoint);
adjustLayout();
}
mPreMovePointF.set(mCurMovePointF);
break;
}
return true;
}
/**
* 獲得四個點和View的年夜小
* @param left
* @param top
* @param right
* @param bottom
* @param degree
*/
private void computeRect(int left, int top, int right, int bottom, float degree){
Point lt = new Point(left, top);
Point rt = new Point(right, top);
Point rb = new Point(right, bottom);
Point lb = new Point(left, bottom);
Point cp = new Point((left + right) / 2, (top + bottom) / 2);
mLTPoint = obtainRoationPoint(cp, lt, degree);
mRTPoint = obtainRoationPoint(cp, rt, degree);
mRBPoint = obtainRoationPoint(cp, rb, degree);
mLBPoint = obtainRoationPoint(cp, lb, degree);
//盤算X坐標最年夜的值和最小的值
int maxCoordinateX = getMaxValue(mLTPoint.x, mRTPoint.x, mRBPoint.x, mLBPoint.x);
int minCoordinateX = getMinValue(mLTPoint.x, mRTPoint.x, mRBPoint.x, mLBPoint.x);;
mViewWidth = maxCoordinateX - minCoordinateX ;
//盤算Y坐標最年夜的值和最小的值
int maxCoordinateY = getMaxValue(mLTPoint.y, mRTPoint.y, mRBPoint.y, mLBPoint.y);
int minCoordinateY = getMinValue(mLTPoint.y, mRTPoint.y, mRBPoint.y, mLBPoint.y);
mViewHeight = maxCoordinateY - minCoordinateY ;
//View中間點的坐標
Point viewCenterPoint = new Point((maxCoordinateX + minCoordinateX) / 2, (maxCoordinateY + minCoordinateY) / 2);
offsetX = mViewWidth / 2 - viewCenterPoint.x;
offsetY = mViewHeight / 2 - viewCenterPoint.y;
int halfDrawableWidth = mDrawableWidth / 2;
int halfDrawableHeight = mDrawableHeight /2;
//將Bitmap的四個點的X的坐標挪動offsetX + halfDrawableWidth
mLTPoint.x += (offsetX + halfDrawableWidth);
mRTPoint.x += (offsetX + halfDrawableWidth);
mRBPoint.x += (offsetX + halfDrawableWidth);
mLBPoint.x += (offsetX + halfDrawableWidth);
//將Bitmap的四個點的Y坐標挪動offsetY + halfDrawableHeight
mLTPoint.y += (offsetY + halfDrawableHeight);
mRTPoint.y += (offsetY + halfDrawableHeight);
mRBPoint.y += (offsetY + halfDrawableHeight);
mLBPoint.y += (offsetY + halfDrawableHeight);
mControlPoint = LocationToPoint(controlLocation);
}
/**
* 依據地位斷定掌握圖標處於誰人點
* @return
*/
private Point LocationToPoint(int location){
switch(location){
case LEFT_TOP:
return mLTPoint;
case RIGHT_TOP:
return mRTPoint;
case RIGHT_BOTTOM:
return mRBPoint;
case LEFT_BOTTOM:
return mLBPoint;
}
return mLTPoint;
}
/**
* 獲得變長參數最年夜的值
* @param array
* @return
*/
public int getMaxValue(Integer...array){
List<Integer> list = Arrays.asList(array);
Collections.sort(list);
return list.get(list.size() -1);
}
/**
* 獲得變長參數最年夜的值
* @param array
* @return
*/
public int getMinValue(Integer...array){
List<Integer> list = Arrays.asList(array);
Collections.sort(list);
return list.get(0);
}
/**
* 獲得扭轉某個角度以後的點
* @param viewCenter
* @param source
* @param degree
* @return
*/
public static Point obtainRoationPoint(Point center, Point source, float degree) {
//二者之間的間隔
Point disPoint = new Point();
disPoint.x = source.x - center.x;
disPoint.y = source.y - center.y;
//沒扭轉之前的弧度
double originRadian = 0;
//沒扭轉之前的角度
double originDegree = 0;
//扭轉以後的角度
double resultDegree = 0;
//扭轉以後的弧度
double resultRadian = 0;
//經由扭轉以後點的坐標
Point resultPoint = new Point();
double distance = Math.sqrt(disPoint.x * disPoint.x + disPoint.y * disPoint.y);
if (disPoint.x == 0 && disPoint.y == 0) {
return center;
// 第一象限
} else if (disPoint.x >= 0 && disPoint.y >= 0) {
// 盤算與x正偏向的夾角
originRadian = Math.asin(disPoint.y / distance);
// 第二象限
} else if (disPoint.x < 0 && disPoint.y >= 0) {
// 盤算與x正偏向的夾角
originRadian = Math.asin(Math.abs(disPoint.x) / distance);
originRadian = originRadian + Math.PI / 2;
// 第三象限
} else if (disPoint.x < 0 && disPoint.y < 0) {
// 盤算與x正偏向的夾角
originRadian = Math.asin(Math.abs(disPoint.y) / distance);
originRadian = originRadian + Math.PI;
} else if (disPoint.x >= 0 && disPoint.y < 0) {
// 盤算與x正偏向的夾角
originRadian = Math.asin(disPoint.x / distance);
originRadian = originRadian + Math.PI * 3 / 2;
}
// 弧度換算成角度
originDegree = radianToDegree(originRadian);
resultDegree = originDegree + degree;
// 角度轉弧度
resultRadian = degreeToRadian(resultDegree);
resultPoint.x = (int) Math.round(distance * Math.cos(resultRadian));
resultPoint.y = (int) Math.round(distance * Math.sin(resultRadian));
resultPoint.x += center.x;
resultPoint.y += center.y;
return resultPoint;
}
/**
* 弧度換算成角度
*
* @return
*/
public static double radianToDegree(double radian) {
return radian * 180 / Math.PI;
}
/**
* 角度換算成弧度
* @param degree
* @return
*/
public static double degreeToRadian(double degree) {
return degree * Math.PI / 180;
}
/**
* 依據點擊的地位斷定能否點中掌握扭轉,縮放的圖片, 初略的盤算
* @param x
* @param y
* @return
*/
private int JudgeStatus(float x, float y){
PointF touchPoint = new PointF(x, y);
PointF controlPointF = new PointF(mControlPoint);
//點擊的點到掌握扭轉,縮放點的間隔
float distanceToControl = distance4PointF(touchPoint, controlPointF);
//假如二者之間的間隔小於 掌握圖標的寬度,高度的最小值,則以為點中了掌握圖標
if(distanceToControl < Math.min(mDrawableWidth/2, mDrawableHeight/2)){
return STATUS_ROTATE_ZOOM;
}
return STATUS_DRAG;
}
public float getImageDegree() {
return mDegree;
}
/**
* 設置圖片扭轉角度
* @param degree
*/
public void setImageDegree(float degree) {
if(this.mDegree != degree){
this.mDegree = degree;
transformDraw();
}
}
public float getImageScale() {
return mScale;
}
/**
* 設置圖片縮放比例
* @param scale
*/
public void setImageScale(float scale) {
if(this.mScale != scale){
this.mScale = scale;
transformDraw();
};
}
public Drawable getControlDrawable() {
return controlDrawable;
}
/**
* 設置掌握圖標
* @param drawable
*/
public void setControlDrawable(Drawable drawable) {
this.controlDrawable = drawable;
mDrawableWidth = drawable.getIntrinsicWidth();
mDrawableHeight = drawable.getIntrinsicHeight();
transformDraw();
}
public int getFramePadding() {
return framePadding;
}
public void setFramePadding(int framePadding) {
if(this.framePadding == framePadding)
return;
this.framePadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, framePadding, metrics);
transformDraw();
}
public int getFrameColor() {
return frameColor;
}
public void setFrameColor(int frameColor) {
if(this.frameColor == frameColor)
return;
this.frameColor = frameColor;
mPaint.setColor(frameColor);
invalidate();
}
public int getFrameWidth() {
return frameWidth;
}
public void setFrameWidth(int frameWidth) {
if(this.frameWidth == frameWidth)
return;
this.frameWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, frameWidth, metrics);
mPaint.setStrokeWidth(frameWidth);
invalidate();
}
/**
* 設置掌握圖標的地位, 設置的值只能選擇LEFT_TOP ,RIGHT_TOP, RIGHT_BOTTOM,LEFT_BOTTOM
* @param controlLocation
*/
public void setControlLocation(int location) {
if(this.controlLocation == location)
return;
this.controlLocation = location;
transformDraw();
}
public int getControlLocation() {
return controlLocation;
}
public PointF getCenterPoint() {
return mCenterPoint;
}
/**
* 設置圖片中間點地位,絕對於父結構而言
* @param mCenterPoint
*/
public void setCenterPoint(PointF mCenterPoint) {
this.mCenterPoint = mCenterPoint;
adjustLayout();
}
public boolean isEditable() {
return isEditable;
}
/**
* 設置能否處於可縮放,平移,扭轉狀況
* @param isEditable
*/
public void setEditable(boolean isEditable) {
this.isEditable = isEditable;
invalidate();
}
/**
* 兩個點之間的間隔
* @param x1
* @param y1
* @param x2
* @param y2
* @return
*/
private float distance4PointF(PointF pf1, PointF pf2) {
float disX = pf2.x - pf1.x;
float disY = pf2.y - pf1.y;
return FloatMath.sqrt(disX * disX + disY * disY);
}
}
為了讓SingleTouchView居中,我們須要獲得父結構的長和寬,我們在onMeasure()中來獲得,固然假如我們不須要居中顯示我們也能夠挪用setCenterPoint辦法來設置其地位.
onTouchEvent()辦法中,mPreMovePointF和mCurMovePointF點的坐標不是絕對View來的,起首假如采取絕對於View自己(getX(), getY())確定是不可的,假設你往x軸偏向挪動一段間隔,這個SingleTouchView也會挪動一段間隔,mPreMovePointF和mCurMovePointF點和SingleTouchView的中間點都是會變更的,所以在挪動的時刻會一直的閃耀,絕對於屏幕左上角(getRawX(), getRawY())是可以的,然則因為mCenterPointF其實不是絕對於屏幕的坐標,而是絕對於父類結構的,所以將須要將mPreMovePointF和mCurMovePointF的坐標換算成絕對於父類結構。
這外面最主要的辦法就是transformDraw()辦法,它重要做的是挪用computeRect()辦法求出圖片的四個角的坐標點mLTPoint,mRTPoint,mRBPoint,mLBPoint(這幾點的坐標是絕對於SingleTouchView自己)和SingleTouchView的寬度和高度,和掌握圖標地點圖標四個點中的哪一個點。以下圖

下面的圖疏忽了掌握扭轉,縮放圖標,黑色的框是開端的View的年夜小,而經由扭轉以後,VIew的年夜小釀成最外層的虛線框了,所以我們須要挪用adjustLayout()辦法來從新設置View的地位和年夜小,接上去就是設置Matrix了
matrix.setScale(mScale, mScale); matrix.postRotate(mDegree % 360, bitmapWidth/2, bitmapHeight/2); matrix.postTranslate(offsetX + mDrawableWidth/2, offsetY + mDrawableHeight/2);
先設置縮放比例, 然後設置環繞圖片的中間點扭轉mDegree,postTranslate( float dx, float dy)辦法是畫該圖片的肇端點停止平移dx, dy個單元,而不是挪動到dx,dy這個點。
接上去就來應用,界說一個xml結構文件
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<com.example.singletouchview.SingleTouchView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/SingleTouchView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:scale="1.2"
app:src="@drawable/scale"
app:frameColor="#0022ff"
app:controlLocation="right_top"/>
</merge>
在外面寫了一些自界說的屬性,寫自界說屬性之前須要聲明xmlns:app="http://schemas.android.com/apk/res-auto",Activity只須要設置這個結構文件作為ContentView就好了,接上去運轉法式看下後果。

怎樣樣?後果照樣不錯的吧,假如我們想去失落藍色的邊框和用於縮放扭轉的小圖標,直接挪用setEditable(false)便可以了,設置了setEditable(false)該View的點擊事宜,長按事宜是正常的。
以上就是本文的全體內容,願望對年夜家進修Android軟件編程有所贊助。