Android自定义控件 ShapeDrawable、Paint、圆形进度条

1、Android资源目录:

   第一类 通过R 生成 id的 文件
   第二类 assert 原文件 
 Android 应用资源目录: 
 /res/animator/   存放属性动画xml
 /res/anim/   存放补间动画
 /res/color
 /res/drawable
 /res/menu   :存放 各种菜单 资源
 /res/raw  : 存放原生 文件,会被R引用
 /res/xml :  存储xml原生文件 


    LoadImageView

// 1.  基本资源
  Resources res= getResources();
        res.getXXX()  //   根据资源清单ID 来获取资源   getString() 、getDrawable
        getAssets()   //   获取assert 下 AssertManager 对象

//2.  数组资源

    
    
        
    

    
    
        
    

2、  使用android api   ShapeDrawable 【图形绘制】  drawText  【文本绘制】

 代码实现:

package mk.denganzhi.com.shapemodel;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.RectShape;
import android.graphics.drawable.shapes.RoundRectShape;
import android.graphics.drawable.shapes.Shape;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by denganzhi on 2020/3/2.
 */

public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }


    ShapeDrawable shapeDrawable=null;
    Paint paint=null;

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        /**
         * ArcShape:     圆弧
         * OvalShape:  椭圆形    默认
         * RectShape    矩形
         * RoundRectShape  圆角矩形
         */
        // 绘制一个矩形
        shapeDrawable=new ShapeDrawable(new OvalShape());
        // 指定背景颜色
        shapeDrawable.getPaint().setColor(Color.RED);
        // 指定路径在View中的
        // int left, int top, int right, int bottom
        //  right,bottom是右下角相对于左边,上边距离
        shapeDrawable.setBounds(10,10,100,100);

        //设置画笔
        paint=new Paint();
        paint.setColor(Color.BLACK);
        paint.setTextSize(20);
        paint.setTypeface(Typeface.DEFAULT_BOLD);  // 设置粗体
        paint.setAntiAlias(true);  // 消除锯齿
    }


    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
        // canvas 画板,背景色
        canvas.drawColor(Color.GREEN);


   // 这个坐标点的镇正确理解:
  // 文字"hello.viwe"的 左小角 相对于 canvas 右上角的的距离
        canvas.drawText("hello.view",10,120,paint);


        // 可以自己把自己画到画布上去
        shapeDrawable.draw(canvas);

    }
}

   使用:

效果图: 

Android自定义控件 ShapeDrawable、Paint、圆形进度条_第1张图片

绘图api归纳:

//  重写onDraw 方法api 
// 1. canvas  用于绘制图片 、 图片到 View 上   2. canvas 变换api
//  Paint 画笔,设置 绘图样式
//  path 绘图路径 

3、 画笔Paint 属性设置

2.1 绘制 直线
  2.2. 文本api 绘制测量, 每一个文本都有一个文本矩形区域
  2.3. 基线问题:
  https://blog.csdn.net/dreams_deng/article/details/104858115
  DrawText基线问题; 
 代码: 

 

        
    

 Java代码实现: 

package com.denganzhi.cusomerwidget.View;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * Created by Administrator on 2018/10/23.
 */

public class PaintView extends View {

    Paint paint;
    private String str = "牛叔fbcdef";

    // 在代码中使用空间的时候New
    public PaintView(Context context) {
        super(context);
    }
    // 在布局文件中配置的时候New
    public PaintView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        // -----------------1.画笔API--------------------
        paint =new Paint();
        //  重置
        paint.reset();
        paint.setTextSize(40);
        paint.setColor(Color.RED);
        //其中,参数x为透明度,取值范围为0~255,数值越小越透明。直接setAlpha是改变整个view的透明度
        paint.setAlpha(255);
        // 1. 设置画笔样式
      //  paint.setStyle(Paint.Style.FILL); //填充
        // 填充和描边,填充是填充圆内部区域
        // 描边是边  圆的半径= 填充/2+描边/2
      //  paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setStyle(Paint.Style.STROKE);  //描边
    //    paint.setStrokeWidth(10);

        // 2. 线帽,比如进度条
//		paint.setStrokeCap(Paint.Cap.BUTT);//没有
		paint.setStrokeCap(Paint.Cap.ROUND);//圆形
//        paint.setStrokeCap(Paint.Cap.SQUARE);//方形


       // 3. 两个线条交接地方
// 	    paint.setStrokeJoin(Paint.Join.MITER);//锐角
//		paint.setStrokeJoin(Paint.Join.ROUND);//圆弧
		paint.setStrokeJoin(Paint.Join.BEVEL);//直线

        //4. 防锯齿,会损失一定的性能
		paint.setAntiAlias(true);
//		//设置是否使用图像抖动处理。会使绘制的图片等颜色更加的清晰以及饱满。(也是损失性能)
//		paint.setDither(true);
    }

    public PaintView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
       // -----------------2.绘制 直线--------------------
        // 1.画圆
//        canvas.drawCircle(100,100,100,paint);
        // 2.画线  实心   -|  效果
//          canvas.drawLine(100,100,400,100,paint);
//          canvas.drawLine(400,100,400,400,paint);

        //3.  使用path绘制 绘制大于符号
        // 使用paint绘制矩形,要绘制4次
		Path path1 = new Path();
        path1.moveTo(100, 100);   // 坐标(100,100)
        path1.lineTo(300, 100);   // 坐标(300,100)  直线
        path1.lineTo(100, 300);   // 坐标(100,300)
        paint.setStrokeJoin(Paint.Join.ROUND);
		canvas.drawPath(path1, paint);


        // 使用path绘制圆角矩形,一个角的圆角大一点
     //   RectF r = new RectF(100, 100, 400, 500);
      //  Path path = new Path();
      //  float radii[] = {10,10,10,10,10,10,50,60};  // 这里要绘制圆角矩形,四个角,每个角一个椭圆(x,y)指定长轴和短轴
	//	path.addRoundRect(r, radii, Direction.CCW);
//		path.addArc(oval, startAngle, sweepAngle)
	//	canvas.drawPath(path, paint);



       // -----------------3.文本api 绘制测量, 每一个文本都有一个文本矩形区域--------------------
        //获得字符行间距
        paint.getFontSpacing();
        //获得字符之间的间距
	//	paint.getLetterSpacing();
	//	paint.setLetterSpacing(letterSpacing)//设置
        //设置文本删除线
        paint.setStrikeThruText(true);
        //是否设置下划线
		paint.setUnderlineText(true);
        //设置文本大小
		paint.setTextSize(80);
//		paint.getTextSize();

		paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));//设置字体类型,加粗
//		Typeface.ITALIC
//		Typeface.create(familyName, style)//加载自定义字体
        //文字倾斜 默认0,官方推荐的-0.25f是斜体
		paint.setTextSkewX(-0.25f);
        //文本对齐方式
		paint.setTextAlign(Paint.Align.LEFT);
//		paint.setTextAlign(Paint.Align.CENTER);
//		paint.setTextAlign(Align.RIGHT);

        paint.setColor(Color.RED);

        // 这个坐标点的镇正确理解:
        // 文字"hello.viwe"的 左小角 相对于 canvas 右上角的的距离
        canvas.drawText(str,200,200,paint);


        // 获取文字的宽、高
		float[] measuredWidth = new float[1];
        // 参数: 字符串、是否从头开始测量、最大值测量的(超过不测量)、测量结果
		int breakText = paint.breakText(str, true, Integer.MAX_VALUE, measuredWidth);
		Log.e("denganzhi1", "字符个数="+breakText+", 字符串长度="+str.length()+", measredWidth:"+measuredWidth[0]);

         //获取文本的宽度,和上面类似,但是是一个比较粗略的结果
  		float measureText = paint.measureText(str);
        Log.e("denganzhi1", "measureText="+measureText);

        //		//measuredWidth得到每一个字符的宽度;textWidths字符数
        float[] measuredWidth2 = new float[10];
		int textWidths = paint.getTextWidths(str, measuredWidth2);
		mPaint.getTextWidths(text, start, end, widths)
		Log.e("denganzhi1", "字符个数:"+textWidths+"   measuredWidth2:"+measuredWidth2[0]);

        // Rect bounds获取文本的矩形区域(宽高),获取指定区域文字的宽、高  index:文字开始 count:文字后面数量
//		mPaint.getTextBounds(text, index, count, bounds)
//		mPaint.getTextBounds(text, start, end, bounds)

    }
}

效果: 

Android自定义控件 ShapeDrawable、Paint、圆形进度条_第2张图片

4、   android  Canvas使用归纳

   1.  画线
   2.  画点
   3.  画矩形
   4.  画圆弧
   5.  矩形运算、合并
   6.  canvas图层变换:
   xml布局:




    


    


Java代码归纳:

package com.denganzhi.cusomerwidget.canvas;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RegionIterator;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * Created by Administrator on 2020/3/15.
 */

public class CanvasView extends View {
    public CanvasView(Context context) {
        super(context);
    }

    Paint paint=null;
    public CanvasView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint=new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(5);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // -------------------- Canvas 绘制基础图形使用  --------------------
        // 1.画线
        //canvas.drawLine(0,0,100,100,paint);
        float []pts = {0,0,100,100,200,200,300,300};
       // canvas.drawLines(pts, paint);  //绘制线,线条之间有间隔
      //  canvas.drawLines(pts, 20, 2, paint);//通过offset设置线的间隔距离,可以实现虚线效果  ??无法使用
// path 画线条
         Path pathLien=new Path();
        pathLien.moveTo(100, 100);//画笔落笔的位置
        pathLien.lineTo(200, 100);
        pathLien.lineTo(200, 200);  // 通过path绘制横竖 -|
       // canvas.drawPath(pathLien, paint);


         // 2.画点
        canvas.drawPoint(500,500,paint);
        //画多个点
       // canvas.drawPoints(pts,paint);


        //3. 画矩形
        //Rect 和 RectF 一个参数为Int 一个参数为float
        RectF rect=new RectF(10,10,200,200);
        // canvas.drawRect(rect,paint);
        // 圆角矩形 , 四个圆角 半径30,30
      //  canvas.drawRoundRect(rect,30,30,paint);
        // 通过path制定 圆角矩形各个 叫的弧度 , 四个角x,y路径
        float radii[] = {10,10,10,10,10,10,50,60};
        Path path = new Path(); // 使用path绘制矩形
        path.addRoundRect(rect, radii, Path.Direction.CCW);
       // canvas.drawPath(path, paint);



        // 4. 画圆弧  true 是否闭合
       // canvas.drawArc(rect,0,30,true,paint);
      // 画圆
       // canvas.drawOval(rect,paint);


        // 5、 矩形合并
        Rect rectF1=new Rect(100,100,300,300);
        Region region=new Region(200,300,400,400);
        region.union(rectF1);
     //   region.op(rectF1, Path.Op.DIFFERENCE)  集合运行,合并、交集、减去

        RegionIterator regionIterator=new RegionIterator(region);
        Rect r2=new Rect();
        while(regionIterator.next(r2)){
         //   canvas.drawRect(r2,paint);
        }

        // -------------------- Canvas 变化  --------------------
        RectF canvasF1=new RectF(0,0,200,200);
      //  canvas.drawRect(canvasF1,paint);
        // 1.画布平移, 会创建一个新的画布,进行平移绘制
     //   canvas.translate(50,50);
     //   canvas.drawRect(canvasF1,paint);
      // 2. 缩放
        // 下面绘制的,在画布上绘制了
       // canvas.scale(2,2);
        // 导致里面绘制的东西有一个缩放效果2.0倍
       // canvas.drawRect(canvasF1,paint);

        // 3. 旋转
        // 画板选择,坐标系选择,绘制内容也变化
        // 0,0 旋转坐标
//        canvas.rotate(60,0,0);
//        canvas.drawRect(canvasF1,paint);

        // 4. 画布斜拉
        //float sx, float sy 这里如何计算   tan60 = 1.73
//        canvas.skew(1.73f,0);
//        canvas.drawRect(canvasF1,paint);

   // 5. 画布裁剪
    //    canvas.clipRect(new Rect(0,0,50,50));
        // 画布填充背景色
      //  canvas.drawColor(Color.BLUE);

    }
}

5、 android 自定义控件,圆形进度条

  3.1.   res/values/attrs.xml 属性设置
  3.2. onDraw  
  初始化画笔,画圆,圆的 半径 末点指向 圆弧的一半
  画文本
  画圆弧
  3.3. postInvalidate 属性UI
  4.4. 提供回调刷新UI

   3.1.   res/values/attrs.xml 属性设置




     
    
        
        
        
        
        
        
        
        
        
        
            
            
        

    

  3.2. onDraw   [MyCircleView.java类]

  3.3. postInvalidate 属性UI

package com.denganzhi.cusomerwidget.View;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import com.denganzhi.cusomerwidget.R;

/**
 * Created by Administrator on 2018/10/24.
 */

public class  MyCircleView extends View {

    private Paint paint;

    int context_text= 0;

    private int max;
    private int roundColor;
    private int roundProgressColor;
    private int textColor;
    private float textSize;
    private float roundWidth;
    private boolean textShow;
    private int style;
    private int progress;

    public interface ListenerLoaingStatus{
        void showLoadingStatus(float value);
    };
    ListenerLoaingStatus listenerLoaingStatus;

    public void setListenerLoaingStatus(ListenerLoaingStatus listenerLoaingStatus) {
        this.listenerLoaingStatus = listenerLoaingStatus;
    }

    public MyCircleView(Context context) {
        super(context);
    }

    public MyCircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint=new Paint();

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyCircleView);
        max = typedArray.getInteger(R.styleable.MyCircleView_max, 100);
        roundColor = typedArray.getColor(R.styleable.MyCircleView_roundColor, Color.RED);
        roundProgressColor = typedArray.getColor(R.styleable.MyCircleView_roundProgressColor, Color.BLUE);
        textColor = typedArray.getColor(R.styleable.MyCircleView_textColor, Color.GREEN);
        textSize = typedArray.getDimension(R.styleable.MyCircleView_textSize, 55);
        roundWidth = typedArray.getDimension(R.styleable.MyCircleView_roundWidth, 50);
        textShow = typedArray.getBoolean(R.styleable.MyCircleView_textShow, true);
        style = typedArray.getInt(R.styleable.MyCircleView_style, 0);

        typedArray.recycle();

    }

    public MyCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //圆的半径包括圆弧厚度的一半,所以rondWidth/2
        // 画圆, 圆的 半径 末点指向 圆弧的一半
        float radious = getWidth()/2 - roundWidth/2;
//        Log.e("denganzhi1","getWidth:"+getWidth()+" radious: "+radious);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(roundWidth);
        canvas.drawCircle(getWidth()/2,getHeight()/2,radious,paint);


        // 绘制文本内容
        // 如何水平、垂直居中:https://blog.csdn.net/dreams_deng/article/details/104858115
        paint.setStrokeWidth(0);
        paint.setColor(textColor);
        paint.setTextSize(100);
        paint.setTypeface(Typeface.DEFAULT_BOLD);
        // 内容居中
        FontMetrics fontMetrics = paint.getFontMetrics();
        //float viewBaseLineY=  getHeight()/2+ ((fontMetrics.bottom-fontMetrics.top)/2- fontMetrics.bottom);
        context_text= (int)((getProgress()*1.0/max)*100);
       // Log.e("denganzhi1","context_text--->:"+context_text+"%");
        float baseLineX = getWidth()/2 -  paint.measureText(context_text+"%")/2;
        float baseLineY =  getHeight()/2 + ((fontMetrics.bottom-fontMetrics.top)/2-fontMetrics.bottom);
        canvas.drawText(context_text+"%",baseLineX,baseLineY,paint);


        // 画圆弧  RectF的理解,RectF必须相交圆圆弧的roundWidth/2处
        // 不是 内切矩形、也是圆的外切矩形
        paint.setStrokeWidth(roundWidth);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        RectF oval = new RectF(roundWidth/2,roundWidth/2, getWidth()-roundWidth/2, getHeight()-roundWidth/2);
      //  canvas.drawRect(oval,paint);

        float progressValue= getProgress()*3.6f;

        canvas.drawArc(oval , 0, progressValue, false, paint);

        listenerLoaingStatus.showLoadingStatus(progressValue);

    }
    public synchronized int getProgress() {
        return progress;
    }

    public synchronized void setProgress(int progress) {
        if(progress>max){
            progress=100;
        }
        this.progress = progress;
// 这里会不断的调用onDraw方法绘制UI
        postInvalidate();
    }

}

RectF的理解:

Android自定义控件 ShapeDrawable、Paint、圆形进度条_第3张图片

  3.4. 提供回调刷新UI

package com.denganzhi.cusomerwidget;

import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;

import com.denganzhi.cusomerwidget.View.MyCircleView;
import com.denganzhi.cusomerwidget.View.MyView1;

public class NormalApiActivity extends AppCompatActivity {
    MyCircleView myarc;
     int progress = 0;
    MyView1 mynew2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_normal_api);

        myarc = (MyCircleView)findViewById(R.id.myarc);
    // 不断调用 postValidate ,不断onDraw方法 绘制UI
        myarc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {


                    @Override
                    public void run() {
                        while (progress <= 100) {
                            progress += 2;
                            myarc.setProgress(progress);
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();
            }
        });

        // 回调 监听内部传递出来的值
        myarc.setListenerLoaingStatus(new MyCircleView.ListenerLoaingStatus() {
            @Override
            public void showLoadingStatus(float value) {
                Log.e("denganzhi1","value:"+value);
            };
        });
    }

}

UI 效果图:

Android自定义控件 ShapeDrawable、Paint、圆形进度条_第4张图片

你可能感兴趣的:(Android,UI)