zoukankan      html  css  js  c++  java
  • 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();

    }

  • 相关阅读:
    高级(线性)素数筛
    Dijkstra(迪杰斯特拉)算法
    简单素数筛
    【解题报告】 POJ1958 奇怪的汉诺塔(Strange Tower of Hanoi)
    4 jQuery Chatting Plugins | jQuery UI Chatbox Plugin Examples Like Facebook, Gmail
    Web User Control Collection data is not storing
    How to turn on IE9 Compatibility View programmatically in Javascript
    从Javascrip 脚本中执行.exe 文件
    HtmlEditorExtender Ajax
    GRIDVIEW模板中查找控件的方式JAVASCRIPT
  • 原文地址:https://www.cnblogs.com/xiaoxiaing/p/5846155.html
Copyright © 2011-2022 走看看