澳门新莆京手机网站-新蒲京娱乐场 > 书籍 > (ST)进度条从0%变到100%、3个造型来回不停切换

(ST)进度条从0%变到100%、3个造型来回不停切换

由来三个自定义的圈子进度条就产生了,是还是不是很简短。源码下载

2. 思路解析


再有部分得以重写的法子

1.onKeyDown(卡塔尔国 当按下有个别键盘时2.onKeyUp()当松手某些键盘时3.onTrackballEvent(卡塔尔国 当发生轨迹球事件时4.onSizeChange(卡塔尔(قطر‎当该器件的轻重缓急被匡正时5.onFinishInflate(State of Qatar回调方法,当使用从XML加载该器件并用它创设分界面之后调用的法子 6.onWindowFocusChanged 当该零部件获得、失去宗旨时7.onAttachedToWindow(State of Qatar当把该器件归入到有些窗口时8.onDetachedFromWindow(卡塔尔当把该构件从有个别窗口上分别时接触的秘诀9.onWindowVisibilityChanged 当包括该器件的窗口的可以知道性产生退换时接触的章程

MainActivity.class:

自定义视图

2.2 3个模样来回切换思路解析

1>:首先先安装刚进来app时私下认可显示的形制,比如私下认可让展现圆;
2>:然后在onDraw(卡塔尔(قطر‎方法中让画圆、画星型、画三角;
3>:然后在自定义的ShapeView中的最下直面外提供叁个改观形象的exchange(卡塔尔方法,在在那之中决断:
假若当前造型是圆,那么就切换为长方形;
万大器晚成当前形象是正方形,那么就切换为三角;
若果当前形态是三角,那么就切换为圆;
在exchange(卡塔尔(قطر‎方法中,因为形象须要持续的更改,所以必需调用invalidate(卡塔尔方法来再一次绘制。
实际代码如下:

/**
 * Email: 2185134304@qq.com
 * Created by JackChen 2018/3/19 8:55
 * Version 1.0
 * Params:
 * Description:   3个形状来回切换(圆形、正方形、三角)
 *
 *
 *    思路就是:
 *          1>:首先设置刚进入app时,默认的形状,比如为圆
 *          2>:在onDraw()方法中 画圆、画正方形、画三角;
 *          3>:然后对外提供一个 exchange()方法,作用是根据当前形状判断:
 *              如果当前形状是圆,就把它改变为正方形;
 *              如果当前形状是正方形,就把它设置为三角;
 *              如果当前形状是三角,就把它设置为圆;
 *
*/

public class ShapeView extends View {

    // 当前形状默认是圆
    private Shape mCurrentShape = Shape.Circle;
    // 画笔
    private Paint mPaint ;
    // 画三角的路径
    private Path mPath ;

    public ShapeView(Context context) {
        this(context,null);
    }

    public ShapeView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ShapeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 初始化画笔
        initPaint() ;
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec) ;
        int height = MeasureSpec.getSize(heightMeasureSpec) ;

        // 获取最小值 为了保证是正方形
        setMeasuredDimension(Math.min(width , height) , Math.min(width , height));
    }


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

        switch (mCurrentShape){
            case Circle:
                 // 画圆
                 int center = getWidth()/2 ;
                 mPaint.setColor(Color.YELLOW);
                 canvas.drawCircle(center , center , center , mPaint);
                 break;
            case Square:
                 // 画正方形
                 mPaint.setColor(Color.BLUE);
                 canvas.drawRect(0,0,getWidth(),getHeight(),mPaint);
                 break;
            case Triangle:
                 // 画等边三角形 Path 画路线
                 mPaint.setColor(Color.RED);
                 if (mPath == null){
                     // 画路径
                     mPath = new Path() ;
                     mPath.moveTo(getWidth()/2 , 0);
                     mPath.lineTo(0 , (float) ((getWidth()/2)*Math.sqrt(3)));
                     mPath.lineTo(getWidth() , (float) ((getWidth()/2)*Math.sqrt(3)));
//                     mPath.lineTo(getWidth()/2,0);
                     mPath.close();  // 把路径闭合,或者用上边lineTo即可
                 }
                 canvas.drawPath(mPath,mPaint);
                 break;
        }
    }


    public void exchange(){
        switch (mCurrentShape){
            case Circle:
                 // 如果是圆,就把当前形状置为正方形
                 mCurrentShape = Shape.Square;
                 break;
            case Square:
                 // 如果是正方形,就把当前形状置为三角
                 mCurrentShape = Shape.Triangle;
                 break;
            case Triangle:
                 // 如果是三角,就把当前形状置为圆
                 mCurrentShape = Shape.Circle ;
                 break;
        }
        // 因为形状不断的变化,所以需要不断的重新绘制
        invalidate();
    }

    private void initPaint() {
        mPaint = new Paint() ;
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
    }


    public enum Shape{
        Circle , Square , Triangle
    }
}

activity_main.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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.jackchen.view_day05_2.MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="切换"
        android:onClick="exchange"
        />

    <com.jackchen.view_day05_2.ShapeView
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_centerInParent="true"
        android:id="@+id/shape_view"
        />

</RelativeLayout>

在MainActivity中援引代码如下:

public class MainActivity extends AppCompatActivity {

    private ProgressBar progress_bar ;
    private ShapeView shape_view;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 切换形状的控件
        shape_view = (ShapeView) findViewById(R.id.shape_view);
    }


    /**
     * 点击 "切换形状" 让3个形状来回不断的切换
     * @param view
     */
    public void exchange(View view){

        // 开一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {

                // 让其不断的循环 ,在这里更新UI,每循环一次,休息一秒钟
                while (true){
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            shape_view.exchange();
                        }
                    });


                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }
}

切实代码已上传至github:
https://github.com/shuai999/View_day05_2.git

自定义随手指移动的小球来上学自定义View

图片 10.gif

福衢寿车地方的功效大家大概须要分成这几步:1.在res/values/ 下树立叁个attrs.xml 来声称自定义view的习性2.一个无冕View并复写一些函数的自定义view的类3.三个来得自定义view 的器皿分界面

1.自定义view命名称叫cicleview,它有三个属性值,格式为color:

<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="cicleview"> <attr name="TextColor" format="color"/> </declare-styleable> </resources>

2.在布局函数获取获得view的习性配置和复写onDraw和onTouchEvent函数达成绘制分界面和顾客事件响应。

public class cicleview extends View{ //定义画笔和初始位置 Paint p = new Paint(); public float currentX = 50; public float currentY = 50; public int textColor; public cicleview(Context context, AttributeSet attrs) { super(context, attrs); //获取资源文件里面的属性,由于这里只有一个属性值,不用遍历数组,直接通过R文件拿出color值 //把属性放在资源文件里,方便设置和复用 TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.myView); textColor = array.getColor(R.styleable.myView_TextColor,Color.BLACK); array.recycle(); } @Override protected void onDraw(Canvas canvas) { super.onDraw; //画一个蓝色的圆形 p.setColor(Color.BLUE); canvas.drawCircle(currentX,currentY,30,p); //设置文字和颜色,这里的颜色是资源文件values里面的值 p.setColor(textColor); canvas.drawText("BY finch",currentX-30,currentY+50,p); } @Override public boolean onTouchEvent(MotionEvent event) { currentX = event.getX(); currentY = event.getY(); invalidate();//重新绘制图形 return true; }}

这里通过不断的换代当前地点坐标和再一次绘制图形达成效果与利益,要稳重的是应用TypedArray后自然要记得recycle(卡塔尔. 不然会对下一次调用发生影响。

3.把cicleview加入到activity_main.xml布局里面

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:andro xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:myview="http://schemas.android.com/apk/res-auto" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="finch.scu.cn.myview.MainActivity"> <com.lee.demo.cicleview android:layout_width="match_parent" android:layout_height="match_parent" myview:TextColor="#ff0000" /></RelativeLayout>
 canvas.drawArc() :绘制一个扇形或者一段弧形 canvas.drawCircle():绘制一个圆形 canvas.drawOval():绘制一个椭圆 canvas.drawLine():绘制一条线 canvas.drawPoint():绘制一个点 canvas.drawRect():绘制一个矩形 canvas.drawRoundRect():绘制一个圆角矩形 canvas.drawVertices():绘制一个顶点 cnavas.drawPath():绘制一条路径

activity_main.xmln内容如下:

2.1 相近QQ运动步数思路解析

职能如下:

图片 2

图片.png

1>:那个进程条是从0% 变化到 100%,和QQ运动步数思路后生可畏致,效果分为3个部分:
第一有个别:外圆背景;
其次局地:内圆背景;
其三部分:变化的文字;
2>:定义3个画笔,分别用来画外圆弧、画内圆弧、画进度的文字;
3>:在自定义的ProgressBar类中的最上边,额外写2个艺术,用来设置最大进程和日前速度,因为脚下速度是天天变动的,所以在现阶段进程方法中必须不断的重复绘制;
4>:在activity_main.xml布局文件中引用本身写的自定义的ProgressBar那样的一个进程条的控件,然后findViewById找到控件后,接受属性动漫让圆环跑起来,给属性动画增多监听器,在品质动漫更新的时候,不断的取妥善前的进程,然后设置给当下进程的点子就可以兑现;
具体代码如下:

/**
 * Email: 2185134304@qq.com
 * Created by JackChen 2018/3/18 18:14
 * Version 1.0
 * Params:
 * Description:   进度条持续变化 从 0% 变到 100%
*/
public class ProgressBar extends View {

    // 内部的背景
    private int mInnerBackground = Color.RED ;
    // 外部的背景
    private int mOuterBackground = Color.RED ;
    // 圆弧的宽度
    private int mRoundWidth = 10 ;  // 10px
    // 进度文字的大小
    private int mProgressTextSize = 15 ;
    // 进度文字的颜色
    private int mProgressTextColor = Color.RED ;


    private Paint mInnerPaint, mOuterPaint, mTextPaint;

    private int mMax = 100 ;
    private int mProgress = 0 ;

    public ProgressBar(Context context) {
        this(context , null);
    }

    public ProgressBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs , 0);
    }

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

        // 获取自定义属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProgressBar);
        // 内部的背景
        mInnerBackground = array.getColor(R.styleable.ProgressBar_innerBackground , mInnerBackground) ;
        // 外部的背景
        mOuterBackground = array.getColor(R.styleable.ProgressBar_outerBackground , mOuterBackground) ;
        // 圆弧的宽度
        mRoundWidth = (int)array.getDimension(R.styleable.ProgressBar_roundWidth , dip2px(10)) ;
        // 字体大小
        mProgressTextSize = array.getDimensionPixelSize(R.styleable.ProgressBar_progressTextSize , sp2px(mProgressTextSize)) ;
        // 字体颜色
        mProgressTextColor = array.getColor(R.styleable.ProgressBar_progressTextColor , mProgressTextColor) ;

        array.recycle();

        mInnerPaint = new Paint();
        mInnerPaint.setAntiAlias(true);
        mInnerPaint.setColor(mInnerBackground);
        mInnerPaint.setStrokeWidth(mRoundWidth);
        mInnerPaint.setStyle(Paint.Style.STROKE);

        mOuterPaint = new Paint();
        mOuterPaint.setAntiAlias(true);
        mOuterPaint.setColor(mOuterBackground);
        mOuterPaint.setStrokeWidth(mRoundWidth);
        mOuterPaint.setStyle(Paint.Style.STROKE);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(mProgressTextColor);
        mTextPaint.setTextSize(mProgressTextSize);

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = MeasureSpec.getSize(widthMeasureSpec) ;
        int height = MeasureSpec.getSize(heightMeasureSpec) ;

        // 获取宽高最小值  保证它是正方形
        setMeasuredDimension(Math.min(width , height) , Math.min(width , height));
    }


    @Override
    protected void onDraw(Canvas canvas) {
//        super.onDraw(canvas);
        // 1. 先画内圆
        int center = getWidth() / 2;
        canvas.drawCircle(center, center, center - mRoundWidth / 2, mInnerPaint);

        // 2. 画外圆
        RectF rect = new RectF(0 + mRoundWidth / 2, 0 + mRoundWidth / 2,
                getWidth() - mRoundWidth / 2, getHeight() - mRoundWidth / 2);

        if (mProgress ==0){
            return;
        }
        float percent = (float) mProgress / mMax;
        canvas.drawArc(rect, 0, percent * 360, false, mOuterPaint);


        // 画进度的文字
        String text = ((int)(percent*100)) + "%" ;
        Rect textBounds = new Rect() ;
        mTextPaint.getTextBounds(text , 0, text.length() , textBounds);

        int x = getWidth()/2 - textBounds.width()/2 ;
        Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();

        int dy = (fontMetrics.bottom - fontMetrics.top)/2 - fontMetrics.bottom ;
        int baseLine = getHeight()/2 + dy ;
        canvas.drawText(text , x , baseLine , mTextPaint);


    }

    private int sp2px(float sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
    }

    private float dip2px(int dip) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
    }


    /**
     * 给几个方法,让它动起来
     * 下边设置 synchronized 目的就是为了防止多个 线程同时操作一个资源,可能会出问题,而添加synchronized后,可以避免这个问题
     * 比如说:一次有两个线程,分别是线程1和线程2
     *        如果不加synchronized:那么线程1和线程2可能会同时执行该方法,可能会出问题
     *        如果加了synchronized:可以避免两个线程同时操作该方法,因为加了synchronized后,如果线程1先执行,它会把这个方法锁住,不让线程2进来,
     *                             当线程1执行完后,线程2才可以执行这个方法
     */

    // 设置最大进度
    public synchronized void setMax(int max){
        if (max < 0){

        }
        this.mMax = max ;
    }


    // 设置当前进度
    public synchronized void setProgress(int progress){
        if (progress < 0){

        }
        this.mProgress = progress ;
        // 因为效果是一直在变,所以这里需要不断重绘
        invalidate();
    }
}

activity_main.xm.构造文件如下:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.jackchen.view_day05_2.MainActivity">
s
    <com.jackchen.view_day05_2.ProgressBar
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:innerBackground="@color/colorPrimary"
        app:outerBackground="@color/colorAccent"
        app:roundWidth="20dp"
        app:progressTextSize="20sp"
        app:progressTextColor="@color/colorAccent"
        android:id="@+id/progress_bar"
        />

</RelativeLayout>

在MainActivity中央直属机关接援用就能够,具体代码如下:

public class MainActivity extends AppCompatActivity {

    private ProgressBar progress_bar ;
    private ShapeView shape_view;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 进度条变化的控件
        progress_bar = (ProgressBar) findViewById(R.id.progress_bar);
        // 设置最大进度
        progress_bar.setMax(4000);
        // 采用属性动画让圆环跑起来
        ValueAnimator animator = ObjectAnimator.ofFloat(0, 4000);
        animator.setDuration(2000) ;
        animator.start();
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //不断的获取当前进度,然后给ProgressBar 设置
                float progress = (float) animation.getAnimatedValue();
                progress_bar.setProgress((int) progress);
            }
        });
    }
}

什么样措施须求被重写

  • onDraw(卡塔尔view中onDraw(卡塔尔是个空函数,也正是说具体的视图都要覆写该函数来贯彻协调的绘图。对于ViewGroup则不须求完毕该函数,因为作为容器是“未有内容“的(但不得不贯彻dispatchDraw(卡塔尔函数,告诉子view绘制本身)。
  • onLayout(卡塔尔首固然为viewGroup类型布局子视图用的,在View中那一个函数为空函数。
  • onMeasure(卡塔尔(قطر‎用于总结视图大小的方法,并经过setMeasuredDimension (width, heightState of Qatar 保存总计结果。
  • onTouch伊夫nt()定义触屏事件来响应客户操作。
package edu.sqchen.circleprogressview;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.graphics.RectF;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;/** * Created by Administrator on 2017/6/1. */public class CircleProgressView extends View { //圆环的宽度 private int ringWidth; //圆环填充颜色 private int ringColor; //进度条填充颜色 private int progressColor; //文字大小 private int textSize; //文字颜色 private int textColor; //画笔 private Paint mPaint; //当前进度值 private int progressSize; //控件本身的宽度 private int mWidth; /** * * @param context */ public CircleProgressView(Context context) { this(context,null); } public CircleProgressView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); mPaint.setAntiAlias; //获取属性值 TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CircleProgressView); //第二个参数是当我们没有给这个控件对应的属性赋值时采用的默认值 ringWidth =  ta.getDimension(R.styleable.CircleProgressView_ringWidth,20); ringColor = ta.getColor(R.styleable.CircleProgressView_ringColor, Color.GRAY); progressColor = ta.getColor(R.styleable.CircleProgressView_progressColor,Color.BLUE); textSize =  ta.getDimension(R.styleable.CircleProgressView_textSize,60); textColor = ta.getColor(R.styleable.CircleProgressView_textColor,Color.BLACK); progressSize = ta.getInteger(R.styleable.CircleProgressView_progressSize,60); //回收TypedArray ta.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec)); mWidth = getMeasuredWidth(); } /** * 对宽度进行判断 * @param widthMeasureSpec * @return */ private int measureWidth(int widthMeasureSpec) { int resultWidth = 0; //获取设置的测量模式和大小 int specMode = MeasureSpec.getMode(widthMeasureSpec); int specSize = MeasureSpec.getSize(widthMeasureSpec); //如果是精确值模式,则宽度等于用户设置的宽度 if(specMode == MeasureSpec.EXACTLY) { resultWidth = specSize; } else { //否则,设置默认值为400个像素,如果是最大值模式,则取用户设置的值和默认值中较小的一个 resultWidth = 400; if(specMode == MeasureSpec.AT_MOST) { resultWidth = Math.min(resultWidth,specSize); } } return resultWidth; } /** * 对高度进行判断 * @param heightMeasureSpec * @return */ private int measureHeight(int heightMeasureSpec) { int resultHeight = 0; int specMode = MeasureSpec.getMode(heightMeasureSpec); int specSize = MeasureSpec.getSize(heightMeasureSpec); if(specMode == MeasureSpec.EXACTLY) { resultHeight = specSize; } else { resultHeight = 400; if(specMode == MeasureSpec.AT_MOST) { resultHeight = Math.min(resultHeight,specSize); } } return resultHeight; } @Override protected void onDraw(Canvas canvas) { //获取圆心坐标及半径 float circleX = mWidth / 2; float circleY = mWidth / 2; float radius = mWidth / 2 - ringWidth / 2; //绘制圆环 mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(ringWidth); mPaint.setColor(ringColor); canvas.drawCircle(circleX,circleY,radius,mPaint); //绘制圆弧,填充进度 //RectF用于构造一个矩形区域,作为传入的椭圆对象 RectF oval = new RectF(ringWidth / 2,ringWidth / 2,mWidth - ringWidth / 2,mWidth - ringWidth / 2); mPaint.setColor(progressColor); //drawArc()方法参数: //1、圆弧所在的椭圆对象 //2、圆弧的起始角度 //3、圆弧的角度 //4、是否显示半径连线 //5、绘制时采用的画笔 canvas.drawArc(oval,0,progressSize * 360 / 100,false,mPaint); //绘制文本 String progressText = progressSize + "%"; //设置画笔颜色和文字大小 mPaint.setColor(textColor); mPaint.setTextSize; //重置画笔宽度,因为前面绘制圆环和圆弧时用到的画笔宽度不一样 mPaint.setStrokeWidth; //构造一个矩形区域,用于放置文本 Rect bound = new Rect(); mPaint.getTextBounds(progressText,0,progressText.length; canvas.drawText(progressText,mWidth / 2 - bound.width() / 2,mWidth / 2 + bound.height() / 2,mPaint); } /** * 获取进度值 * @return */ public int getProgressSize() { return progressSize; } /** * 设置进度值 * @param progressSize */ public void setProgressSize(int progressSize) { this.progressSize = progressSize; }}

6.基于百分比,慢慢更动圆锥形的深浅,逐步减小圆柱形的平底y轴的坐标,不断重绘,直到到达100%

1. 说明


据悉后边大家写的自定义View入门、自定义TextView、仿QQ运动步数、玩转字体变色后,大家那节课再来写三个功用:
首先个:相像QQ运动步数,那是个进程条,效果是从0%变到100%;
其次个:3个形象不断切换

意气风发体起立,奏国歌.行注目礼!

能够见到,我们对传递步入的宽高进行度量情势的判断,假诺是准确值情势,则接纳顾客设置的切实上升的幅度,不然推断是或不是是最大值方式,则取客商安装的值(即wrap_content)和默许值400像素中一点都不大的非常值。

几日前无形中中开采三个圆形进程,动脑本人达成叁个,如下图:

View的绘图进程

图片 3View的绘图进度

笔者们要贯彻的是二个圆形进程条控件,中间的公文动态展现当前行度值,如图:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="circlecolor" format="color"></attr>
    <attr name="half" format="dimension"></attr>

    <declare-styleable name="myCircleImage">
        <attr name="circlecolor"></attr>
        <attr name="half"></attr>
    </declare-styleable>

</resources>

贯彻步骤

  1. 接轨View类或其子类
  2. 复写view中的一些函数
  3. 为自定义View类扩展属性
  4. 绘图控件
  5. 一倡百和客商事件
  6. 概念回调函数(依据本人须求来抉择)
 //绘制圆弧,填充进度 //RectF用于构造一个矩形区域,作为传入的椭圆对象 RectF oval = new RectF(ringWidth / 2,ringWidth / 2,mWidth - ringWidth / 2,mWidth - ringWidth / 2); mPaint.setColor(progressColor); //drawArc()方法参数: //1、圆弧所在的椭圆对象 //2、圆弧的起始角度 //3、圆弧的角度 //4、是否显示半径连线 //5、绘制时采用的画笔 canvas.drawArc(oval,0,progressSize * 360 / 100,false,mPaint);

概念绘制圆形的背景象,和制图圆形的半径大小

前言

在Android应用开辟进程中,固定的有的控件和质量恐怕满意不断开荒的急需,所以在部分异样意况下,大家需求自定义控件与性能,同样,那也是面试中面试官问的概率相比高的难点,也是由初级技术员通向中高工必备的。

 //获取圆心坐标及半径 float circleX = mWidth / 2; float circleY = mWidth / 2; float radius = mWidth / 2 - ringWidth / 2; //绘制圆环 mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(ringWidth); mPaint.setColor(ringColor); canvas.drawCircle(circleX,circleY,radius,mPaint);

1.先是绘制二个实心圆

自定义属性的三种艺术

  • 在布局文件中直接插手属性,在布局函数中去得到。

结构文件:

<RelativeLayout xmlns:andro android:layout_width="match_parent" android:layout_height="match_parent" > <com.lee.demo.initView android:layout_width="wrap_content" android:layout_height="wrap_content" inittext="@string/hello_world" /></RelativeLayout>

在布局方法中

public initView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub int textId = attrs.getAttributeResourceValue(null, "inittext", 0); String text = context.getResources().getText.toString();}
  • 在res/values/ 下创立叁个attrs.xml 来声称自定义view的品质。

可以定义的习性有:

<declare-styleable name = "名称"> //参考某一资源ID (name可以随便命名)<attr name = "background" format = "reference" /> //颜色值 <attr name = "textColor" format = "color" /> //布尔值<attr name = "focusable" format = "boolean" /> //尺寸值 <attr name = "layout_width" format = "dimension" /> //浮点值 <attr name = "fromAlpha" format = "float" /> //整型值 <attr name = "frameDuration" format="integer" /> //字符串 <attr name = "text" format = "string" /> //百分数 <attr name = "pivotX" format = "fraction" /> //枚举值 <attr name="orientation"> <enum name="horizontal" value="0" /> <enum name="vertical" value="1" /> </attr> //位或运算 <attr name="windowSoftInputMode"> <flag name = "stateUnspecified" value = "0" /> <flag name = "stateUnchanged" value = "1" /> </attr> //多类型<attr name = "background" format = "reference|color" /> </declare-styleable>
  • attrs.xml举办品质注明
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="myView"> <attr name="text" format="string"/> <attr name="textColor" format="color"/> </declare-styleable></resources>
  • 增进到布局文件
<RelativeLayout xmlns:andro android:layout_width="match_parent" android:layout_height="match_parent" xmlns:myview="http://schemas.android.com/apk/com.example.demo" > <com.lee.demo.initView android:layout_width="wrap_content" android:layout_height="wrap_content" myview:text = "test" myview:textColor ="#ff0000" /></RelativeLayout>
  • 此地注意命名空间:xmlns:前缀="

  • 在布局函数中拿到属性值

public initView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.myView); String text = a.getString(R.styleable.myView_text); int textColor = a.getColor(R.styleable.myView_textColor, Color.WHITE); a.recycle(); }

或者:

 public initView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.myView); int n = a.getIndexCount(); for(int i=0;i<n;i++){ int attr = a.getIndex; switch  { case R.styleable.myView_text: break; case R.styleable.myView_textColor: break; } } a.recycle(); }

能够入手工编织码了。新建贰个类CircleProgressView 继承自View,达成布局方法,同等对待写onDraw()onMeasure()方法,如下:

3.在圆的主干动态绘制当前行度的百分比字符

自定义控件的二种艺术

1.接续本来就有的控件 当要兑现的控件和已部分控件在众多方面前蒙受比周围, 通过对本来就有控件的恢弘来满意必要。2.继承一个布局文件 日常用于自定义组合控件,在布局函数中经过inflater和addView(卡塔尔(قطر‎方法加载自定义控件的布局文件产生图形分界面(无需onDraw方法)。3.延续view 通过onDraw方法来绘制出组件分界面。

自定义属性设置好了,像前边说的,能够在第五个结构方法中获取那些自定义属性的值,由于没有须要在java代码中实例化创立该控件,能够在前三个布局方法中调用第多少个布局方法。平日也把有个别开始化操作放在结构方法中,例如我们这里运用的画笔Paint的开首化,代码如下:

2.绘制八个灰色实心的圆柱形,遮住实心圆

attrs.xml

在activity_main.xml中,须求用到自定义的品质,首先增加命名空间: xmlns:liu=”

接下去思量恐怕要用到的回调方法,onDraw()艺术是必得的,因为这是叁个全新的控件。onMeasure()内需用到吧?今后大概还不明了,等到具体达成的时候可能就知道了。

4.制图一个与事前实心圆相符颜色的空心圆

 Paint.setAntiAlias():抗锯齿 Paint.setStyle():设置画笔风格 Paint.setStrokeWidth():设置画笔宽度 Paint.setColor():设置画笔颜色 Paint.setTextSize():设置画笔绘制文本的文字大小
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class CirclePro extends View {

    private Paint paint;
    private int circleBack;//圆的背景色
    private int mschedual = 0;//用于控制动态变化
    float circleHalf; //圆的半径
    String percent = "";//绘制百分比的字符串

    @SuppressLint("Recycle")
    public CirclePro(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint = new Paint();
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.myCircleImage, defStyleAttr,0);
        @SuppressWarnings("unused")
        int leng = array.length();
        //获取自定义的属性,这里注意是R.styleable.myCircleImage_circlecolor而不是R.attr.circlecolor
        circleBack = array.getColor(R.styleable.myCircleImage_circlecolor,Color.GREEN);
        circleHalf = array.getDimension(R.styleable.myCircleImage_half,200.f);
        System.out.println(circleBack);

    }

    /**
     * 这个构造参数,当在布局文件中引用该view的时候,必须重写该构造函数
     * @param context
     * @param attrs
     */
    public CirclePro(Context context, AttributeSet attrs) {
        this(context, attrs, 0);//调用自己的构造函数

    }

    /**
     * 根据文本的
     * @param text
     * @param textSize
     * @return
     */
    public float getTextWidth(String text,float textSize) {

        TextPaint textPaint = new TextPaint();
        textPaint.setTextSize(textSize);
        return textPaint.measureText(text);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);

        float height = getHeight();
        float width = getWidth();
//      float circleHalf = (float) (width*0.7/2);

        paint.setColor(circleBack);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(width/2,height/2,circleHalf, paint);//画实心圆

        if (mschedual <= 100) {//,如果当前进度小于100,画实心矩形
            paint.setColor(Color.WHITE);
            canvas.drawRect(width/2-circleHalf,height/2-circleHalf,width/2+circleHalf,height/2+circleHalf - mschedual*circleHalf/50, paint);
        }

        //画当前进度的字符串
        paint.setColor(Color.BLACK);
        paint.setTextSize(30.f);
        percent = mschedual+" %";
        canvas.drawText(percent, width/2-getTextWidth(percent,30)/2,height/2+paint.getTextSize()*3/8, paint);//字体的高度=paint.getTextSize()*3/4

        //画空心圆
        paint.setColor(circleBack);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(width/2,height/2,circleHalf, paint);

        if (mschedual < 100) {//更改当前进度值,并重绘
            mschedual++;
            invalidate();
        }
    }
}

接下来深入分析应该什么绘制那样多个控件。它由一个圆环、一个圆弧、生龙活虎段文本组成,那么很明朗了,必要多个步骤:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:liu="http://schemas.android.com/apk/res/com.example.androidcirclepro"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.example.androidcirclepro.CirclePro
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        liu:half="90dp"
        liu:circlecolor="#fff0f0"
        />

</RelativeLayout>

控件自个儿的小幅能够在onMeasure()方法中得到到:

首先探访自定义的品质

 /** * 当在java代码中直接new一个控件实例的时候,调用此构造方法 */ public CircleProgressView(Context context) { super; } /** * 当在XML文件中直接使用该控件的时候, * 并且该控件由自定义属性的时候,调用此构造方法 */ public CircleProgressView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } /** * 系统默认只调用前两个构造方法, * 此方法通常是我们在前两个构造方法中调用, * 用于获取自定义属性的值 */ public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }

基本思路是如此的:

就算有了那几个属性,不过当大家在采取那一个控件的时候,该怎样给那一个属性赋值呢?那就必要用到布局方法了。多个布局方法的运用如下:

其间liu是自定义的多少个前缀,随便命名的,com.example.androidcirclepro是大家的应用的包名

在完毕自定义控件的时候,大家每每必要对控件进行度量、绘制、和构造等操作。

在values目录下新建attrs.xml内容如下:

绘图圆环:

5.逐步改换近些日子的比重

前面大家在activity_main.xml中给控件的宽高设置为切实指,那么大器晚成旦要安装为wrap_content呢?修改activity_main.xml

图片 4

[图表上传战败...(image-ae6aeb-1513606785650卡塔尔国]

Copyright © 2015-2019 http://www.carrefourstation.com. 澳门新莆京手机网站-新蒲京娱乐场有限公司 版权所有