3个自定义view布局:矩形TextView,圆形进度条,圆环view

注:本文3个自定义view布局共用使用一个xml文件,


1.自定义矩形TextView的view

package com.bwie.CustomView.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.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.TextView;
import com.bwie.CustomView.R;

/**
 自定义矩形TextView的view

*/
public class CustomTextView extends TextView{
    private String text;
    private int color;
    private Paint paint;
    private int size;
    private Rect rect;

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

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //通过context.obtainStyledAttributes()方法读取自定义view的属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        //获取自定义view的属性的数量
        int count = typedArray.getIndexCount();
        //通过下标获取自定义view的属性
        for (int i=0;i<count;i++){
            int indexAttr = typedArray.getIndex(i);
            switch (indexAttr){
                //获取自定义view的text属性
                case R.styleable.CustomTextView_text:
                    text = typedArray.getString(indexAttr);
                    break;
                //获取自定义view的color属性,先设置一个默认颜色
                case R.styleable.CustomTextView_textColor:
                    color = typedArray.getInt(indexAttr, Color.YELLOW);
                    break;
                //获取自定义view的size属性
                case R.styleable.CustomTextView_textSize:
                    //通过下面前2行代码的方法转换获取的size属性数据
                    DisplayMetrics metrics = getResources().getDisplayMetrics();
                    float dimension = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 18, metrics);
                    size = typedArray.getDimensionPixelSize(indexAttr, (int) dimension);
                    break;
            }
        }
        //数据不用时,回收以下
        typedArray.recycle();

        //设置画笔的size
        paint = new Paint();
        paint.setTextSize(size);

        //设置一个矩形。对text内容进行测量
        rect = new Rect();
        paint.getTextBounds(text,0,text.length(),rect);
    }

    /**
     *  onMeasure方法:计算子控件的尺寸和模式,以及设置自己的宽和高,测量View大小
        widthMeasureSpec:当前父容器的widthMeasureSpec
        heightMeasureSpec:当前父容器的heightMeasureSpec
        使用的是onMeasure函数,关于三种测量模式mode说法:
     (1)EXACTLY:一般是设置了明确的值(100dp)或者是MATCH_PARENT;
     (2)AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT;
     (3)UNSPECIFIED:表示子布局想要多大就多大,很少使用;
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //计算当前父容器下view的模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        //计算当前父容器下view的size
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        System.out.println("width = " + width);
        System.out.println("height = " + height);
    }

    //onDraw方法:绘图方法(canvas画布)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //getWidth(): View在设定好布局后,整个View的宽度     getHeight(): View在设定好布局后,整个View的高度
        int widht = getWidth();
        int height = getHeight() ;

        //获取矩形的宽高
        int rectWidth = rect.width();
        int rectHeight = rect.height();

        //设置画笔的颜色
        paint.setColor(Color.YELLOW);
        //drawRect 就是使用画笔绘制一个矩形 前面两个参数代表起始坐标, 也就是左上角 后面两个参数可以标识你想画的长度和宽度 也可以理解为右下角的坐标点。
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);

        //设置画笔画出的内容颜色,设置画出内容的所在位置坐标
        paint.setColor(color);
        /**
         * drawText方法:绘制文字。参数:
         * text:要绘制的文字
         * x:绘制原点x坐标
         * y:绘制原点y坐标
         * paint:用来做画的画笔
         */
        canvas.drawText(text,(getWidth()-rect.width())/2,(getHeight()+rect.height())/2,paint);

        System.out.println("getWidth() = " + getWidth());
        System.out.println("getMeasuredWidth() = " + getMeasuredWidth());
    }

    /**
     *
     * @param w view改变后当前的宽
     * @param h  view改变后当前的高
     * @param oldw  view改变前的宽
     * @param oldh   view改变前的高
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        System.out.println("w = " + w + "  " + h  + " " + oldw + "  " + oldh);
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

 
 
 在values文件夹下的自定义矩形TextView使用的自定义属性xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--在declare-styleable控件中写自定义view的属性-->
    <!--    format表示自定义view属性值的取值类型     -->
    <declare-styleable name="CustomTextView">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
    </declare-styleable>

</resources>

2. 自定义圆形进度条view

package com.bwie.CustomView.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
 * 自定义显示圆形进度条的view
 */
public class CustomProgressView extends View{
    private boolean runing = true;
    private int progress = 0;
    private Paint paint;

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

    public CustomProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //创建一个画笔
        paint = new Paint();

        //设置画笔的颜色
        paint.setColor(Color.BLUE);
        //设置画笔的style:内容是填充的空心圆
        paint.setStyle(Paint.Style.STROKE);

        //执行进度条是耗时操作,需放在子线程中执行
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (runing){
                    if (progress >= 360){
                        runing = false;
                        return;
                    }
                    progress += 10;

                    //子线程刷新方法:postInvalidate(),此事系统会调用onDraw()方法
                    postInvalidate();
                    try {
                        Thread.sleep(188);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //(1)获取当前自定义view的宽高度
        int x = getWidth() / 2;
        int y = getHeight() / 2;

        //(2)设置圆半径的大小
        int radius = 300;

        //(3)设置画笔的粗细
        paint.setStrokeWidth(18);

        //(4)定义一个矩形区域:RectF对象持有一个矩形的四个float坐标值
        RectF rectF = new RectF(x - radius, y - radius, x + radius, y + radius);
        /**
         *  画一个圆弧:drawArc方法:绘制圆弧,该方法用于在画布上绘制圆弧,通过指定圆弧所在的椭圆对象、起始角度、终止角度来实现。
         *   oval:圆弧所在的椭圆对象。
             startAngle:圆弧的起始角度。
             sweepAngle:圆弧的角度。
             useCenter:是否显示半径连线,true表示显示圆弧与圆心的半径连线,false表示不显示。
             paint:绘制时所使用的画笔。
         */
        canvas.drawArc(rectF,-90,progress,false,paint);

        //(5)把progress转换为int值
        int intProgress = (int) ((float)progress/360 * 100);

        //(6) measureText  测量字符串的宽度
        float textWidth = paint.measureText(intProgress + "%");
        //定义一个矩形区域:Rect对象持有一个矩形的四个integer坐标值
        Rect rect = new Rect();
        //测量矩形中内容
        paint.getTextBounds(intProgress+"%",0,(intProgress+"%").length(),rect);

        //设置画笔写出内容的size和画笔的粗细西
        paint.setTextSize(90);
        paint.setStrokeWidth(1);

        //画出文字  rect.height() 获取字符串的高度
        /**
         * drawText方法参数:
         * text:要绘制的文字
         * x:绘制原点x坐标
         * y:绘制原点y坐标
         * paint:用来做画的画笔
         */
        canvas.drawText(intProgress+"%",x-textWidth/2,y+rect.height()/2,paint);
    }

    public CustomProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

3. 自定义圆环view

package com.bwie.CustomView.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
 * 自定义圆环view
 */
public class CustomCircleView extends View{
    private Paint paint;
    private int xCircle = 200;  //圆心的x坐标
    private int yCircle = 200;  //圆心的y坐标
    public CustomCircleView(Context context) {
        super(context);
    }

    //CustomCircleView方法:设置自定义圆形view的视图
    public CustomCircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //设置画笔的颜色,style,setAntiAlias 抗锯齿形式(true为去除锯齿,false则不去),setStrokeWidth方法:设置空心线宽
        paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(80);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                //getRawX()和getRawY()获得的是相对屏幕的位置
                System.out.println("按下时:    x  "+event.getRawX()+"     y  "+event.getRawY());
                break;
            case MotionEvent.ACTION_MOVE:
                //getRawX()和getRawY()获得的是相对屏幕的位置
                System.out.println("移动时:    x  "+event.getRawX()+"     y  "+event.getRawY());

                //获取鼠标移动时的坐标,为X轴和Y轴坐标重新赋值:getX()和getY()获得的永远是view的触摸位置坐标
                xCircle = (int) event.getX();
                yCircle = (int)event.getY();
                /**
                 *  Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:
                    1. Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。
                    invalidate()是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉。
                   2.Android 程序默认情况下也只有一个进程,但一个进程下却可以有许多个线程。在这么多线程当中,把主要是负责控
                        制UI界面的显示、更新和控件交互的线程称为UI线程,由于onCreate()方法是由UI线程执行的,所以也可以把UI线程理解
                        为主线程。其余的线程可以理解为工作者线程。invalidate()得在UI线程中被调动,在工作者线程中可以通过Handler来通
                        知UI线程进行界面更新。而postInvalidate()在工作者线程中被调用。
                 */
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                //getRawX()和getRawY()获得的是相对屏幕的位置
                System.out.println("抬起时:    x  "+event.getRawX()+"     y  "+event.getRawY());
                break;
        }
        return true;
    }

    /**
     * onMeasure方法:计算子控件的尺寸和模式,以及设置自己的宽和高
        widthMeasureSpec:当前父容器的widthMeasureSpec
        heightMeasureSpec:当前父容器的heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    //onDraw方法:绘图方法(canvas画布)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
         * canvas.drawCircle()方法:该方法用于在画布上绘制圆形,通过指定圆形圆心的坐标和半径来实现。该方法是绘制圆形的主要方法,同时也可以通过设置画笔的空心效果来绘制空心的圆形。
         *  cx:圆心的x坐标。
            cy:圆心的y坐标。
            radius:圆的半径。
            paint:绘制时所使用的画笔。
         */
        canvas.drawCircle(xCircle,yCircle,200,paint);
    }

    public CustomCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

4.  3个自定义view共用的xml文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!--    如上:自定义view的布局文件必写属性:xmlns:app="http://schemas.android.com/apk/res-auto"-->

    <!--    自定义矩形TextView的view控件属性  -->
    <!--    自定义view的属性声明时使用   app:     前缀   -->
    <com.bwie.CustomView.view.CustomTextView
        android:layout_centerInParent="true"
        android:layout_marginTop="28dp"
        android:layout_width="188dp"
        android:layout_height="188dp"

        app:textSize="18sp"
        app:text="自定义TextView"
        app:textColor="@color/colorAccent"  />


    <!--    自定义圆形进度条view时的控件属性  -->
<!--    <com.bwie.CustomView.view.CustomProgressView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />-->

    <!--    自定义圆形view时的控件属性  -->
<!--    <com.bwie.CustomView.view.CustomCircleView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />-->

</RelativeLayout>


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值