2019-03-19 自定義View繪制表盤

效果圖:


效果圖


素材:

需求:手指撥動指針,更改還款數字。

源碼:

import android.graphics.*;

import android.support.*;

import android.util.AttributeSet;

import android.util.Log;

import android.util.TypedValue;

import android.view.*;

public class DialTableViewextends View {

private Bitmap btmNormalDial, btmCheckedDial, btmNeedle;

private int needleWidth, needleHeight;//指針精心化控制,寬高比為10:1。指針寬度是半徑的2分之1

? ? private Paint mPaint;

private Path maskPath;//遮罩層路徑

? ? private RectF maskRectF;//遮罩層畫弧度需要的方形區域

? ? private float radius =0;//表盤半徑

? ? private float degrees =0;//指針角度

? ? /**

? ? * @return 角度的浮點值? 0-180之間

? ? */

? ? public float getDegrees() {

return degrees;

}

/**

? ? * @param degrees 角度的浮點值? 0-180之間

? ? */

? ? public void setDegrees(@FloatRange(from =0, to =180)float degrees) {

this.degrees = degrees;

invalidate();

}

/**

? ? * @return 角度的整數值 0-180之間

? ? */

? ? public int getDegreesInt() {

return (int) degrees;

}

/**

? ? * @param degrees 角度的整數值 0-180之間

? ? */

? ? public void setDegreesInt(@IntRange(from =0, to =180)int degrees) {

this.degrees = degrees;

invalidate();

}

/**

? ? * @return 角度的百分比 0-100之間

? ? */

? ? public int getDegreesPer() {

return (int) (degrees *100 /180);

}

/**

? ? * @param percent 角度的百分比 0-100之間

? ? */

? ? public void setDegreesPer(@IntRange(from =0, to =100)int percent) {

this.degrees = percent *180.0f /100;

invalidate();

}

@Override

protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {

//無論寬高設置多少,最終View的高總是取 (width/2 :height)中的最小值,且寬總是高的2倍。

? ? ? ? int measureWidth = MeasureSpec.getSize(widthMeasureSpec);

int measureHeight = MeasureSpec.getSize(heightMeasureSpec);

int measureRadius = Math.min(measureWidth /2, measureHeight);

setMeasuredDimension(measureRadius *2, measureRadius);

}

@Override

protected void onSizeChanged(int w,int h,int oldw,int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

radius = Math.min(w /2, h);

needleWidth = (int) (radius /2);

needleHeight = needleWidth /10;

btmNeedle = getScaledBitmap(R.drawable.needle, needleWidth, needleHeight);

btmNormalDial = getScaledBitmap(R.drawable.dial_normal, (int) (2 * radius), (int) radius);

btmCheckedDial = getScaledBitmap(R.drawable.dial_checked, (int) (2 * radius), (int) radius);

mPaint =new Paint();

mPaint.setAntiAlias(true);

mPaint.setStyle(Paint.Style.FILL);

mPaint.setColor(Color.BLUE);

maskPath =new Path();

maskRectF =new RectF();

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

//計算運算變量

? ? ? ? int width = canvas.getWidth();

int height = canvas.getHeight();

float rotateX = width /2;//旋轉中心X

? ? ? ? float rotateY = height - needleHeight /2;//指針旋轉中心Y有一些偏移

? ? ? ? //canvas.drawColor(Color.GRAY);

? ? ? ? //畫白色

? ? ? ? canvas.save();

canvas.drawBitmap(btmNormalDial,0,0, mPaint);

canvas.restore();

//畫紅色

? ? ? ? canvas.save();

maskPath.reset();

maskPath.moveTo(width /2, height);

maskPath.lineTo(0, height);

maskRectF.set(0,0, width,2 * height);

maskPath.arcTo(maskRectF,180, degrees);

maskPath.close();

canvas.clipPath(maskPath);

canvas.drawBitmap(btmCheckedDial,0,0, mPaint);

canvas.restore();

//畫指針

? ? ? ? canvas.save();

canvas.rotate(degrees, rotateX, rotateY);

canvas.drawBitmap(btmNeedle, width /4 + needleHeight /2, height - needleHeight, mPaint);

canvas.restore();

}

@Override

public boolean onTouchEvent(MotionEvent event) {

if (event.getY() >= radius) {

return true;

}

return gestureDetector.onTouchEvent(event);

}

GestureDetector gestureDetector =new GestureDetector(getContext(),new GestureDetector.SimpleOnGestureListener() {

@Override

public boolean onDown(MotionEvent e) {

//獲取點擊點計算角度,然后開始動畫

? ? ? ? ? ? double pointX = e.getX() - radius;//轉成圓形計算

? ? ? ? ? ? double pointY = e.getY() - radius;//同上

? ? ? ? ? ? double angel = Math.atan2(pointX, pointY);//根據斜率求弧度,tan函數的逆運算

? ? ? ? ? ? int newDegrees = (int) (180 * angel / Math.PI);

if (newDegrees >=90 && newDegrees <=180) {

newDegrees =180 - newDegrees +90;

}else if (newDegrees >= -180 && newDegrees <= -90) {

newDegrees = -newDegrees -90;

}

//Log.i("myk","角度:"+newDegrees+"");

? ? ? ? ? ? degrees = newDegrees;

if (mDegreesChangedListener !=null) {

mDegreesChangedListener.onDegreesChanged(degrees);

}

invalidate();

return true;

}

@Override

public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX,float distanceY) {

double pointX = e2.getX() - radius;//轉成圓形計算

? ? ? ? ? ? double pointY = e2.getY() - radius;//+同上

? ? ? ? ? ? double angel = Math.atan2(pointX, pointY);//根據斜率求弧度,tan函數的逆運算

? ? ? ? ? ? int newDegrees = (int) (180 * angel / Math.PI);

if (newDegrees >=90 && newDegrees <=180) {

newDegrees =180 - newDegrees +90;

}else if (newDegrees >= -180 && newDegrees <= -90) {

newDegrees = -newDegrees -90;

}

//Log.i("myk","角度:"+newDegrees+"");

? ? ? ? ? ? degrees = newDegrees;

invalidate();

if (mDegreesChangedListener !=null) {

mDegreesChangedListener.onDegreesChanged(newDegrees);

}

return true;

}

});

//表盤指針事件監聽

? ? private DegreesChangedListener mDegreesChangedListener;

public void setOnDegreesChangedListener(DegreesChangedListener degreesChangedListener) {

this.mDegreesChangedListener = degreesChangedListener;

}

public interface DegreesChangedListener {

void onDegreesChanged(float newDegrees);

}

private Bitmap getScaledBitmap(@DrawableResint sourceId,int width,int height) {

Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), sourceId);

if (bitmap.getWidth() == width && bitmap.getHeight() == height) {

return bitmap;

}

return Bitmap.createScaledBitmap(bitmap, width, height,true);

}

private int dp2px(Context context,int dip) {

final float scale = context.getResources().getDisplayMetrics().density;

return (int) (dip * scale +0.5f);

}

private int sp2px(Context context,float spValue) {

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, context.getResources().getDisplayMetrics());

}

public DialTableView(Context context) {

this(context,null);

}

public DialTableView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

}

}


后話:

? ? ? ? 這也沒啥技術含量,就是官方的api用用,基本的計算公式擺擺,也不多廢話了。

反正用代碼畫圖挺好玩的,文章里可能會有些你一時沒想到的小技巧吧。

? ? ? ? 本來還想加個屬性動畫的,手指點擊,指針慢慢轉過去,我太懶,以后再寫。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容