Android为TV端助力 转载:android自定义view实战(温度控制表)!
效果圖
?
package cn.ljuns.temperature.view;
import com.example.mvp.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
/**
* 步驟:
* 1、整個背景圓(可有可無)
* 2、進度弧(分為三段,顏色分別為綠黃紅)
* 3、進度弧上的文字(正常,預警,警告)
* 4、刻度弧(緊靠著進度弧內側的黑色弧)
* 5、刻度
* 6、中間的圓
* 7、指針
* 8、當前溫度
*/
public class TemperatureView extends View {
private float progressWidth;
private String tempText;
private float tempTextSize;
private Paint outCirclePaint; // 整個背景圓
private Paint progressPaint; // 進度
private Paint scaleArcPaint; // 刻度弧
private Paint scalePaint; // 刻度
private Paint panelTextPaint; // 表盤文字
private Paint progressTextPaint; // 進度條上的文字
private Paint pointPaint; // 中心圓
private Paint leftPointerPaint; // 表針左半部分
private Paint rightPointerPaint; // 表針右半部分
private Paint pointerCirclePaint; // 表針的圓軸
private int mSize; // 最終的大小
private static final int PADDING = 15; // 進度的寬度
private static final int OFFSET = 5;
private String scale; // 刻度數值
private int mTikeCount = 40; // 40條刻度(包括長短)
private int mLongTikeHeight = dp2px(10); // 長刻度
private int mShortTikeHeight = dp2px(5); // 短刻度
private int progressRadius; // 進度弧的半徑
private int scaleArcRadius = 123; // 刻度弧的半徑
private int pointRadius = dp2px(17); // 中心圓半徑
private float currentTemp;
public TemperatureView(Context context) {
this(context, null);
}
public TemperatureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TemperatureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 獲取自定義屬性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.temperatureProgress);
//Dimension 指尺寸
progressWidth = ta.getDimension(R.styleable.temperatureProgress_progressWidth, PADDING);
//基本數據類型
tempText = ta.getString(R.styleable.temperatureProgress_tempText);
tempTextSize = ta.getDimension(R.styleable.temperatureProgress_tempTextSize, sp2px(15));
ta.recycle();
initPaint();
}
/**
* 測試的寬和高,如果測試的時候設置的寬或者高的屬性不是match_parent,那就把寬高設為默認的200dp
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int realWidth = startMeasure(widthMeasureSpec);
int realHeight = startMeasure(heightMeasureSpec);
Log.i("TAG", "realWidth:"+realWidth);
Log.i("TAG", "realHeight:"+realHeight);
/**
* 因為是以正方形為基礎
*/
mSize = Math.min(realHeight, realWidth);
setMeasuredDimension(mSize, mSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 將畫布移到中央
canvas.translate(mSize /2, mSize /2);
// 畫最外面的圓
drawOutCircle(canvas);
// // 畫進度
drawProgress(canvas);
// // 畫進度上的文字
drawProgressText(canvas);
// // 畫表盤
drawPanel(canvas);
}
/**
* 進度上的文字
* @param canvas
*/
private void drawProgressText(Canvas canvas) {
canvas.save();
String normal = "正常";
String warn = "預警";
String danger = "警告";
// 因為文字在進度弧上,所以要旋轉一定的角度
canvas.rotate(-60, 0, 0);
progressTextPaint.setTextSize(sp2px(12));
Log.i("TAG", "scaleArcRadius:"+scaleArcRadius);
canvas.drawText(normal, -dp2px(12), -scaleArcRadius - dp2px(4), progressTextPaint);
canvas.rotate(90, 0, 0);
canvas.drawText(warn, -dp2px(12), -scaleArcRadius - dp2px(4), progressTextPaint);
canvas.rotate(60, 0, 0);
canvas.drawText(danger, -dp2px(12), -scaleArcRadius - dp2px(4), progressTextPaint);
canvas.rotate(-60, 0, 0);
canvas.restore();
}
/**
* 進度弧
* @param canvas
*/
private void drawProgress(Canvas canvas) {
// dp2px(10):留一點位置(可有可無)
progressRadius = mSize /2 - dp2px(10);
//用來保存Canvas的狀態。save之后,可以調用Canvas的平移、放縮、旋轉、錯切、裁剪等操作
canvas.save();
Log.i("TAG", "progressRadius;:"+progressRadius);
RectF rectF = new RectF(-progressRadius, -progressRadius, progressRadius, progressRadius);
// 設置為圓角
progressPaint.setStrokeCap(Paint.Cap.ROUND);
progressPaint.setColor(Color.GREEN);
// 從150度位置開始,經過120度
canvas.drawArc(rectF, 150, 120, false, progressPaint);
progressPaint.setColor(Color.RED);
progressPaint.setStrokeCap(Paint.Cap.ROUND);
canvas.drawArc(rectF, 330, 60, false, progressPaint);
progressPaint.setColor(Color.YELLOW);
progressPaint.setStrokeCap(Paint.Cap.BUTT);
canvas.drawArc(rectF, 270, 60, false, progressPaint);
// restore:用來恢復Canvas之前保存的狀態。防止save后對Canvas執行的操作對后續的繪制有影響
canvas.restore();
}
/**
* 表盤
* @param canvas
*/
private void drawPanel(Canvas canvas) {
// 畫刻度弧
drawScaleArc(canvas);
// 畫中間圓
drawInPoint(canvas);
// 畫指針
drawPointer(canvas);
// 繪制文字
drawPanelText(canvas);
}
/**
* 表盤上的文字
* @param canvas
*/
private void drawPanelText(Canvas canvas) {
canvas.save();
String text = "當前溫度";
float length = panelTextPaint.measureText(text);
panelTextPaint.setTextSize(sp2px(15));
canvas.drawText(text, -length/2, scaleArcRadius/2 + dp2px(20), panelTextPaint);
String temp = currentTemp + " ℃";
panelTextPaint.setTextSize(sp2px(15));
// panelTextPaint.setColor(tempTextColor);
float tempTextLength = panelTextPaint.measureText(temp);
canvas.drawText(temp, -tempTextLength/2, scaleArcRadius, panelTextPaint);
canvas.restore();
}
/**
* 指針(這里分為左右部分是為了畫出來的指針有立體感)
* @param canvas
*/
private void drawPointer(Canvas canvas) {
RectF rectF = new RectF(-pointRadius/2, -pointRadius/2, pointRadius/2, pointRadius/2);
canvas.save();
// 先將指針與刻度0位置對齊
canvas.rotate(60, 0, 0);
float angle = currentTemp * 6.0f;
canvas.rotate(angle, 0, 0);
// 表針左半部分
Path leftPointerPath = new Path();
leftPointerPath.moveTo(pointRadius/2, 0);//moveTo:設置路徑起始點
leftPointerPath.addArc(rectF, 0, 360);//添加一個圓弧到路徑
leftPointerPath.lineTo(0, scaleArcRadius - mLongTikeHeight - dp2px(OFFSET) - dp2px(15));
leftPointerPath.lineTo(-pointRadius/2, 0);
leftPointerPath.close();//閉合路徑
// 表針右半部分
Path rightPointerPath = new Path();
rightPointerPath.moveTo(-pointRadius/2, 0);
rightPointerPath.addArc(rectF, 0, -180);
rightPointerPath.lineTo(0, scaleArcRadius - mLongTikeHeight - dp2px(OFFSET) - dp2px(15));
rightPointerPath.lineTo(0, pointRadius/2);
rightPointerPath.close();
// 表針的圓
Path circlePath = new Path();
circlePath.addCircle(0, 0, pointRadius/4, Path.Direction.CW);
canvas.drawPath(leftPointerPath, leftPointerPaint);
canvas.drawPath(rightPointerPath, rightPointerPaint);
canvas.drawPath(circlePath, pointerCirclePaint);
canvas.restore();
}
/**
* 中心圓
* @param canvas
*/
private void drawInPoint(Canvas canvas) {
canvas.save();
canvas.drawCircle(0, 0, pointRadius, pointPaint);
canvas.restore();
}
/**
* 刻度弧
* @param canvas
*/
private void drawScaleArc(Canvas canvas) {
// 刻度弧緊靠進度弧
scaleArcRadius = mSize/2 - (dp2px(15)+dp2px(PADDING)/4);
Log.i("TAG", "aaaa:"+scaleArcRadius);
canvas.save();
// 畫弧
RectF rectF = new RectF(-scaleArcRadius, -scaleArcRadius,
scaleArcRadius, scaleArcRadius);
canvas.drawArc(rectF, 150, 240, false, scaleArcPaint);
// 旋轉的角度
float mAngle = 240f / mTikeCount;
// 畫右半部分的刻度
for (int i = 0; i <= mTikeCount/2; i++) {
// 5的倍數就畫長刻度,并標上刻度數值
if (i % 5 == 0) {
scale = 20 + i + "";
panelTextPaint.setTextSize(sp2px(15));
float scaleWidth = panelTextPaint.measureText(scale);
canvas.drawLine(0, -scaleArcRadius, 0, -scaleArcRadius+mLongTikeHeight, scalePaint);
canvas.drawText(scale, -scaleWidth/2, -scaleArcRadius+mLongTikeHeight + dp2px(15), panelTextPaint);
} else {
canvas.drawLine(0, -scaleArcRadius, 0, -scaleArcRadius+ mShortTikeHeight, scalePaint);
}
canvas.rotate(mAngle, 0, 0);
}
// 畫布回正
canvas.rotate(-mAngle * mTikeCount/2 - 6, 0, 0);
// 畫左半部分的刻度
for (int i = 0; i <= mTikeCount/2; i++) {
if (i % 5 == 0) {
scale = 20 - i + "";
panelTextPaint.setTextSize(sp2px(15));
float scaleWidth = panelTextPaint.measureText(scale);
canvas.drawLine(0, -scaleArcRadius, 0, -scaleArcRadius+mLongTikeHeight, scalePaint);
canvas.drawText(scale, -scaleWidth/2, -scaleArcRadius + mLongTikeHeight + dp2px(15), panelTextPaint);
} else {
canvas.drawLine(0, -scaleArcRadius, 0, -scaleArcRadius+ mShortTikeHeight, scalePaint);
}
canvas.rotate(-mAngle, 0, 0);
}
// 畫布回正
canvas.rotate(-mAngle * mTikeCount/2 + 6, 0, 0);
canvas.restore();
}
/**
* 最外面的圓
* @param canvas
*/
private void drawOutCircle(Canvas canvas) {
// 已經將畫布移到中心,所以圓心為(0,0)
canvas.drawCircle(0, 0, mSize /2-dp2px(1), outCirclePaint);
canvas.save();
}
/**
* 測量大小
* @param whSpec
* @return
*/
private int startMeasure(int whSpec) {
int result = 0;
int size = MeasureSpec.getSize(whSpec);
int mode = MeasureSpec.getMode(whSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = dp2px(200);
}
return result;
}
/**
* 將 dp 轉換為 px
* @param dp
* @return
*/
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
private int sp2px(int sp){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
}
/**
* 初始化畫筆
*/
private void initPaint() {
outCirclePaint = new Paint();//外圓漆
progressPaint = new Paint();//進步涂料
scaleArcPaint = new Paint();
scalePaint = new Paint();
panelTextPaint = new Paint();
progressTextPaint = new Paint();
pointPaint = new Paint();
leftPointerPaint = new Paint();
rightPointerPaint = new Paint();
pointerCirclePaint = new Paint();
progressPaint.setAntiAlias(true);
progressPaint.setStrokeWidth(dp2px(PADDING));
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeCap(Paint.Cap.ROUND);
progressPaint.setStrokeJoin(Paint.Join.ROUND);
outCirclePaint.setAntiAlias(true);
outCirclePaint.setStrokeWidth(5);
outCirclePaint.setColor((int) Long.parseLong("ffffffcc", 16));
outCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
// outCirclePaint.setColor(getResources().getColor(R.color.temperatureBackground));
scaleArcPaint.setAntiAlias(true);
scaleArcPaint.setStrokeWidth(dp2px(2));
scaleArcPaint.setStyle(Paint.Style.STROKE);
scalePaint.setAntiAlias(true);
scalePaint.setStrokeWidth(5);
scalePaint.setStyle(Paint.Style.STROKE);
panelTextPaint.setAntiAlias(true);
panelTextPaint.setStyle(Paint.Style.FILL);
panelTextPaint.setColor(Color.BLACK);
progressTextPaint.setAntiAlias(true);
progressTextPaint.setStyle(Paint.Style.FILL);
progressTextPaint.setColor(Color.BLACK);
progressTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
pointPaint.setAntiAlias(true);
pointPaint.setStyle(Paint.Style.FILL);
pointPaint.setColor(Color.GRAY);
leftPointerPaint.setAntiAlias(true);
leftPointerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
leftPointerPaint.setColor(getResources().getColor(R.color.leftPointer));
rightPointerPaint.setAntiAlias(true);
rightPointerPaint.setColor(getResources().getColor(R.color.rightPointer));
rightPointerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
pointerCirclePaint.setAntiAlias(true);
pointerCirclePaint.setColor(Color.GRAY);
pointerCirclePaint.setStyle(Paint.Style.FILL);
pointerCirclePaint.setDither(true);
}
/**
* 設置當前溫度
* @param currentTemp
*/
public void setCurrentTemp(float currentTemp) {
if (currentTemp < 0) {
currentTemp = 0;
} else if (currentTemp > 40) {
currentTemp = 40;
} else {
this.currentTemp = currentTemp;
postInvalidate();
}
}
public float getCurrentTemp() {
return currentTemp;
}
public float getProgressWidth() {
return progressWidth;
}
public void setProgressWidth(float progressWidth) {
this.progressWidth = progressWidth;
}
public String getTempText() {
return tempText;
}
public void setTempText(String tempText) {
this.tempText = tempText;
}
public float getTempTextSize() {
return tempTextSize;
}
public void setTempTextSize(float tempTextSize) {
this.tempTextSize = tempTextSize;
}
}
MainActivity的
public class MainActivity extends Activity implements ILoginView{
private Button button1;
private Button button2;
private EditText edit1;
private EditText edit2;
private ILoginPresenter presenterCompl;
private VelocityTracker vv;
private TemperatureView mTemperatureView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
Log.i("TAG", "Parent:"+getParent());
presenterCompl = new LoginPresenterCompl(this);
// button1 = (Button)findViewById(R.id.button1);
// button2 = (Button)findViewById(R.id.button2);
// edit1 = (EditText)findViewById(R.id.edit1);
// edit2 = (EditText)findViewById(R.id.edit2);
//
// button1.setOnClickListener(new OnClickListener() {
// @Override
// public void onClick(View v) {
// presenterCompl.doLogin(edit1.getText().toString(), edit2.getText().toString());
// }
// });
// button2.setOnClickListener(new OnClickListener() {
// @Override
// public void onClick(View v) {
// presenterCompl.clear();
// }
// });
mTemperatureView = (TemperatureView)findViewById(R.id.temperature_view);
mTemperatureView = (TemperatureView) findViewById(R.id.temperature_view);
new Thread(new Runnable() {
@Override
public void run() {
for (float i = 0; i <=40; i ++) {
mTemperatureView.setCurrentTemp(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
?
轉載于:https://www.cnblogs.com/xiaoxiaing/p/5846155.html
總結
以上是生活随笔為你收集整理的Android为TV端助力 转载:android自定义view实战(温度控制表)!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript push(),jo
- 下一篇: table列宽控制,word-break