Android自定義View圓盤滑動控制元件(已適配多種解析度)
阿新 • • 發佈:2019-02-02
好久沒寫部落格了,最近在寫一個專案時需要一個可以調節檔位的圓盤, 首先實現這個圓盤自定義View,首先在構造方法中定義畫筆,重寫onDraw(Canvas canvas)方法,進行繪製,首先繪製一個大圓,然後我這個大圓周圍的錶盤顯示一共有9個檔位,為了美觀,每個檔位裡面有8個小指標,這樣一個分為72份,也就是沒5°畫一次,由於我這個還需要有一個設定檔位的按鈕,所以新增檔位的檔位設定。
下面說一下滑動手勢的處理
我們可以在oNMeasure()方法得到該控制元件的大小,除以2就是圓心,我們設定的大圓的半徑為200,用圓心y座標減去200就是0檔位的y座標,通過獲取當前手勢位置,就可以通過這三個點構建三角形,通過初中學的餘弦定理可以求得滑動角度,當滑動到左半部分,角度注意要用360-當前角度。
螢幕適配看了hongyang大神Orz的適配方案, http://blog.csdn.net/lmj623565791/article/details/45460089
————————–分割線————————————-
上程式碼
package com.example.yasin.dianretan.utils;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.example.yasin.dianretan.R;
import java.util.Calendar;
/**
* Created by Yasin on 2016/4/7.
*/
public class CirclerView extends View {
private int width;
private int height;
private Paint mPaintLine;
private Paint mPaintCircle;
private Paint mPaintSec;
private Paint mPaintText,mPaintText2;
private int dw;//當前檔位
public static final int NEED_INVALIDATE = 0X23;
private double cx,cy;//手勢座標
private double yxx,yxy;//圓心
private String name;
private double jd;//滑動的角度
//每隔一秒,在handler中呼叫一次重新繪製方法
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case NEED_INVALIDATE:
invalidate();//告訴UI主執行緒重新繪製
handler.sendEmptyMessageDelayed(NEED_INVALIDATE,1000);
break;
default:
break;
}
}
};
public CirclerView(Context context) {
super(context);
}
public CirclerView(Context context, AttributeSet attrs) {
super(context, attrs);
/*
* 定義多個畫不同東西的畫筆
* */
mPaintLine = new Paint();
mPaintLine.setColor(Color.WHITE);
mPaintLine.setStrokeWidth(6);
mPaintCircle = new Paint();
mPaintCircle.setColor(context.getResources().getColor(R.color.yellow));//設定顏色
mPaintCircle.setStrokeWidth(10);//設定線寬
mPaintCircle.setAntiAlias(true);//設定是否抗鋸齒
mPaintCircle.setStyle(Paint.Style.STROKE);//設定繪製風格
mPaintText = new Paint();
mPaintText.setColor(Color.WHITE);
mPaintText.setStrokeWidth(10);
mPaintText.setTextAlign(Paint.Align.CENTER);
mPaintText.setTextSize(40);
mPaintText2 = new Paint();
mPaintText2.setColor(Color.WHITE);
mPaintText2.setStrokeWidth(10);
mPaintText2.setTextAlign(Paint.Align.CENTER);
mPaintText2.setTextSize(60);
//滑針
mPaintSec = new Paint();
mPaintSec.setStrokeWidth(10);
mPaintSec.setColor(Color.YELLOW);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
yxx = width/2;
yxy = height/2;
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int circleRadius = 200;//大圓半徑
//畫出大圓
canvas.drawCircle(width / 2, height / 2, circleRadius, mPaintCircle);
//依次旋轉畫布,畫出每個刻度和對應數字
if(dw==0){
mPaintText2.setColor(Color.RED);
canvas.drawText("關",width/2,height/2+60,mPaintText2);
}else{
mPaintText2.setColor(Color.WHITE);
canvas.drawText(dw+"檔",width/2,height/2+60,mPaintText2);
}
mPaintText2.setColor(Color.YELLOW);
mPaintText2.setTextSize(40);
canvas.drawText(name, width / 2, height / 2 - 50, mPaintText2);
for (int i = 0; i <= 71; i++) {//一共有72個(刻度+檔位文字)
canvas.save();//儲存當前畫布
canvas.rotate(360 / 72 * i, width / 2, height / 2);
// canvas.rotate((float)jd, width / 2, height / 2);
if(i%8!=0) {
if(i<dw*8||i<jd/5.0f){/*如果使用的檔位調節,則該檔位內的都有黃色;
如果滑動的,一個刻度是5°,s所以個當前度數除以5*/
mPaintLine.setColor(Color.YELLOW);
}else{
mPaintLine.setColor(Color.WHITE);
}
canvas.drawLine(width / 2, height / 2 - circleRadius-10, width / 2, height / 2 - circleRadius - 30, mPaintLine);
}else {
//左起:文字內容,起始位置x座標,起始位置y座標,畫筆
if(i/8<=dw){
mPaintText.setColor(Color.YELLOW);
}else{
mPaintText.setColor(Color.WHITE);
}
canvas.drawText("" + i / 8, width / 2, height / 2 - circleRadius - 20, mPaintText);
}
canvas.restore();
}
float secDegree = (float) jd;//dw/9f*360;//得到指標旋轉的角度
canvas.save();
canvas.rotate(secDegree, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 - circleRadius, width / 2, height / 2 - circleRadius - 30, mPaintSec);
canvas.restore();
}
public void setDw(int dw){
this.dw = dw;
//handler.sendEmptyMessage(NEED_INVALIDATE);//向handler傳送一個訊息,讓它開啟重繪
this.jd = dw*40;
invalidate();
}
public int getDw(){
return dw;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
cx=event.getX();
cy=event.getY();
jd = getJD(cx,cy);
if(cx<=yxx) {
jd=180+(180-jd);
}
dw = (int) (jd/40);
invalidate();
return true;
}
/*
* type 1表示得到距離,2表示得到的距離的平方
* */
private double getJL(double ax,double ay,double bx,double by,int type){
if(type==1){
return Math.sqrt(((ax-bx)*(ax-bx)+(ay-by)*(ay-by)));
}else{
return (((ax-bx)*(ax-bx)+(ay-by)*(ay-by)));
}
}
//計算角度
private double getJD(double ax,double ay){
return (Math.acos(((getJL(ax,ay,yxx,yxy,2)+200*200-getJL(ax,ay,yxx,(yxy-200),2))/(2*200*getJL(ax,ay,yxx,yxy,1))))*180/Math.PI);
}
}
效果圖