自定义View

来源:互联网 发布:卡尔曼滤波算法应用 编辑:程序博客网 时间:2024/05/22 00:28

1.组合View

例如:

放在drawable文件下的EditText背景

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#FFFFFF" /><!--<corners android:radius="3dip"/>--><stroke    android:width="1dip"    android:color="#BDC7D8" /></shape>

xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal"    android:weightSum="1">    <TextView        android:id="@+id/txt_delete"        android:layout_width="30dp"        android:layout_height="30dp"        android:text="减"        android:gravity="center"        android:background="#8b948b"/>    <EditText        android:id="@+id/et_number"        android:layout_marginTop="2dp"        android:layout_width="50dp"        android:layout_height="30dp"        android:background="@drawable/edit"        android:layout_weight="0.00"        android:gravity="center"        android:text="1"/>    <TextView        android:id="@+id/txt_add"        android:layout_width="30dp"        android:layout_height="30dp"        android:text="加"        android:gravity="center"        android:background="#8b948b"/></LinearLayout>


自定义控件类class

public class AddDeleteView extends LinearLayout {    private OnAddDelClickListener listener;    private EditText etNumber;    //对外提供一个点击的回调接口    interface OnAddDelClickListener{        void onAddClick(View v);        void onDelClick(View v);    }    public void setOnAddDelClickListener(OnAddDelClickListener listener){        if(listener!=null){            this.listener=listener;        }    }    public AddDeleteView(Context context) {        this(context,null);    }    public AddDeleteView(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public AddDeleteView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(context, attrs, defStyleAttr);    }    private void initView(Context context, AttributeSet attrs, int defStyleAttr) {        View.inflate(context,R.layout.layout_add_delete,this);        //获取控件        TextView txtDelete=findViewById(R.id.txt_delete);        TextView txtAdd=findViewById(R.id.txt_add);        etNumber = findViewById(R.id.et_number);        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AddDeleteViewStyle);        String leftText = typedArray.getString(R.styleable.AddDeleteViewStyle_left_text);        String rightText = typedArray.getString(R.styleable.AddDeleteViewStyle_right_text);        String middleText = typedArray.getString(R.styleable.AddDeleteViewStyle_middle_text);        int color = typedArray.getColor(R.styleable.AddDeleteViewStyle_left_text_color, Color.RED);        txtDelete.setText(leftText);        txtAdd.setText(rightText);        etNumber.setText(middleText);        txtDelete.setTextColor(color);        //回收        typedArray.recycle();        txtDelete.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View view) {                listener.onDelClick(view);            }        });        txtAdd.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View view) {                listener.onAddClick(view);            }        });    }    //对外提供一个修改数字的方法    public void setNumber(int number){        if(number>0){            etNumber.setText(number+"");        }    }    //对外提供一个获取当前数字的方法    public int getNumber(){        String string = etNumber.getText().toString();        int i = Integer.parseInt(string);        return i;    }}


自定义控件属性

//在res/values/中创建arrts

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="AddDeleteViewStyle">        <attr name="left_text" format="string"></attr>        <attr name="right_text" format="string"></attr>        <attr name="middle_text" format="string"></attr>        <attr name="left_text_color" format="color"></attr>    </declare-styleable></resources>


全路径引入

<com.example.xx.day02_viewgroup_view.AddDeleteView        android:id="@+id/adv"        android:layout_width="match_parent"        android:layout_height="wrap_content"        app:left_text="减"        app:right_text="加"        app:middle_text="2"        app:left_text_color="#c8bf40"        >    </com.example.xx.day02_viewgroup_view.AddDeleteView>


activity 控制

public class MainActivity extends AppCompatActivity {    private AddDeleteView adv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        adv = (AddDeleteView) findViewById(R.id.adv);        adv.setOnAddDelClickListener(new AddDeleteView.OnAddDelClickListener() {            @Override            public void onAddClick(View v) {                int number = adv.getNumber();                number++;                adv.setNumber(number);            }            @Override            public void onDelClick(View v) {                int number = adv.getNumber();                number--;                adv.setNumber(number);            }        });    }


2.画View

package com.example.xx.day02_viewgroup_view;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.View;/** * 作者:戈鹏 * on 2017/11/1 20:50 */public class MyView extends View {    public MyView(Context context) {        this(context,null);    }    public MyView(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    /**     * 自定义方法最重要的方法     * Canvas 画布     * @param canvas     */    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //画笔 抗锯齿        Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);        //画笔颜色        paint.setColor(Color.BLUE);        //不填充        paint.setStyle(Paint.Style.STROKE);        //设置粗体        paint.setFakeBoldText(true);        /**         * cx:圆心的x坐标。         * cy:圆心的y坐标。         *radius:圆的半径。         *paint:绘制时所使用的画笔。         */        //画圆  单位是px像素        canvas.drawCircle(DensityUtil.dip2px(getContext(),50),DensityUtil.dip2px(getContext(),50),                            DensityUtil.dip2px(getContext(),50),paint);        //划路径        /*Path path = new Path();        path.moveTo(0,0);        path.lineTo(DensityUtil.dip2px(getContext(),50),DensityUtil.dip2px(getContext(),50));        path.lineTo(0,DensityUtil.dip2px(getContext(),100));        canvas.drawPath(path,paint);*/        //画矩形        /**         * x矩形左上角的 x 坐标         * y矩形左上角的 y 坐标         * width矩形的宽度,以像素计         * height矩形的高度,以像素计         */        paint.reset();        paint.setColor(Color.RED);        /*canvas.drawRect(DensityUtil.dip2px(getContext(),50),                DensityUtil.dip2px(getContext(),70),                DensityUtil.dip2px(getContext(),90),                DensityUtil.dip2px(getContext(),90),paint);*/        canvas.drawCircle(DensityUtil.dip2px(getContext(),50),DensityUtil.dip2px(getContext(),50),                DensityUtil.dip2px(getContext(),40),paint);    }    /**\     * Measure 测量     * @param widthMeasureSpec     * @param heightMeasureSpec     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        //widthSize是控件的宽,单位是px        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        //widthSize是控件的高,单位是px        int heightSize = MeasureSpec.getSize(heightMeasureSpec);       /* widthMode == 1073741824----widthSize == 720         heightMode == -2147483648----heightSize == 1009*/       //测量的3种模式        switch (widthMode){            case MeasureSpec.AT_MOST:  // 有多大占多大,一般是wrap_content                break;            case MeasureSpec.UNSPECIFIED: // 一般我们不怎么用,主要给系统提供了一些设置                break;            case MeasureSpec.EXACTLY: // 精确值,两种情况下模式是EXACTLY,                // 一个就是设置一个固定数值,另一种情况就是设置值是match_parent                break;        }        switch (heightMode){            case MeasureSpec.AT_MOST:  // 有多大占多大,一般是wrap_content                break;            case MeasureSpec.UNSPECIFIED:// 一般我们不怎么用,主要给系统提供了一些设置                break;            case MeasureSpec.EXACTLY:// 精确值,两种情况下模式是EXACTLY,                // 一个就是设置一个固定数值,另一种情况就是设置值是match_parent                break;        }        //设置View最终的宽高  设置  测量 尺寸        setMeasuredDimension(DensityUtil.dip2px(getContext(),200),DensityUtil.dip2px(getContext(),200));    }}

3. 继承VIewGroup. TextView瀑布流



xml:

<com.example.xx.day03_onlayout.MyViewGroup        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:background="#ff0000">        <TextView            android:layout_width="100dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="卢旷行,也不行"/>        <TextView            android:layout_width="130dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="徐蒙伸,想减肥"/>        <TextView            android:layout_width="160dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="老陈飞,特别白"/>        <TextView            android:layout_width="110dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="卢旷行,也不行"/>        <TextView            android:layout_width="90dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="徐蒙伸,想减肥"/>        <TextView            android:layout_width="160dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="老陈飞,特别白"/>        <TextView            android:layout_width="130dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="徐蒙伸,想减肥"/>        <TextView            android:layout_width="160dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="老陈飞,特别白"/>        <TextView            android:layout_width="110dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="卢旷行,也不行"/>        <TextView            android:layout_width="90dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="徐蒙伸,想减肥"/>        <TextView            android:layout_width="160dp"            android:layout_height="30dp"            android:background="#0f0"            android:textColor="#00f"            android:text="老陈飞,特别白"/>    </com.example.xx.day03_onlayout.MyViewGroup>

自定义View类

import android.content.Context;import android.graphics.Canvas;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;/** * 作者:戈鹏 * on 2017/11/2 22:29 */public class MyViewGroup extends ViewGroup {    private int widthSize;    public MyViewGroup(Context context) {        super(context);    }    public MyViewGroup(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //测量子View的宽高,只有ViewGroup中有这个方法,直接继承自View没有这个方法        measureChildren(widthMeasureSpec,heightMeasureSpec);        //获取ViewGrou宽        widthSize = MeasureSpec.getSize(widthMeasureSpec);    }    @Override    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {        int childCount = getChildCount();        int startWidth=5;        int startheight=0;        for (int j = 0; j < childCount; j++) {            View v = getChildAt(j);            //设置位置            v.layout(startWidth,startheight,startWidth+v.getMeasuredWidth()+5,startheight+v.getMeasuredHeight());            startWidth+=v.getMeasuredWidth();            if(startWidth>=widthSize){                startWidth=0;                startheight+=v.getMeasuredHeight()+10;            }        }    }}
dip转px   px转dip工具类

public class DensityUtil {    /**     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)     */    public static int dip2px(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dpValue * scale + 0.5f);    }    /**     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp     */    public static int px2dip(Context context, float pxValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (pxValue / scale + 0.5f);    }}


4.画一个圆形进度条


自定义属性attrs:

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="RoundProgressBar">        <attr name="roundColor" format="color"/>        <attr name="roundProgressColor" format="color"/>        <attr name="roundWidth" format="dimension"></attr>        <attr name="textColor" format="color" />        <attr name="textSize" format="dimension" />        <attr name="max" format="integer"></attr>        <attr name="textIsDisplayable" format="boolean"></attr>        <attr name="style">            <enum name="STROKE" value="0"></enum>            <enum name="FILL" value="1"></enum>        </attr>    </declare-styleable></resources>


自定义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.RectF;import android.graphics.Typeface;import android.util.AttributeSet;import android.util.Log;import android.view.View;/** * 作者:戈鹏 * on 2017/11/4 09:02 */public class RoundProgressBar extends View {    /**     * 画笔对象的引用     */    private Paint paint;    /**     * 圆环的颜色     */    private int roundColor;    /**     * 圆环进度的颜色     */    private int roundProgressColor;    /**     * 中间进度百分比的字符串的颜色     */    private int textColor;    /**     * 中间进度百分比的字符串的字体     */    private float textSize;    /**     * 圆环的宽度     */    private float roundWidth;    /**     * 最大进度     */    private int max;    /**     * 当前进度     */    private int progress;    /**     * 是否显示中间的进度     */    private boolean textIsDisplayable;    /**     * 进度的风格,实心或者空心     */    private int style;    public static final int STROKE = 0;    public static final int FILL = 1;    public RoundProgressBar(Context context) {        this(context, null);    }    public RoundProgressBar(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public RoundProgressBar(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        paint = new Paint();        TypedArray mTypedArray = context.obtainStyledAttributes(attrs,                R.styleable.RoundProgressBar);        //获取自定义属性和默认值        roundColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundColor, Color.RED);        roundProgressColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundProgressColor, Color.GREEN);        textColor = mTypedArray.getColor(R.styleable.RoundProgressBar_textColor, Color.GREEN);        textSize = mTypedArray.getDimension(R.styleable.RoundProgressBar_textSize, 15);        roundWidth = mTypedArray.getDimension(R.styleable.RoundProgressBar_roundWidth, 5);        max = mTypedArray.getInteger(R.styleable.RoundProgressBar_max, 100);        textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgressBar_textIsDisplayable, true);        style = mTypedArray.getInt(R.styleable.RoundProgressBar_style, 0);        mTypedArray.recycle();    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        /**         * 画最外层的大圆环         */        int centre = getWidth()/2; //获取圆心的x坐标        int radius = (int) (centre - roundWidth/2); //圆环的半径        paint.setColor(roundColor); //设置圆环的颜色        paint.setStyle(Paint.Style.STROKE); //设置空心        paint.setStrokeWidth(roundWidth); //设置圆环的宽度        paint.setAntiAlias(true);  //消除锯齿        canvas.drawCircle(centre, centre, radius, paint); //画出圆环        Log.e("log", centre + "");        /**         * 画进度百分比         */        paint.setStrokeWidth(0);        paint.setColor(textColor);        paint.setTextSize(textSize);        paint.setTypeface(Typeface.DEFAULT_BOLD); //设置字体        int percent = (int)(((float)progress / (float)max) * 100);  //中间的进度百分比,先转换成float在进行除法运算,不然都为0        float textWidth = paint.measureText(percent + "%");   //测量字体宽度,我们需要根据字体的宽度设置在圆环中间        //if(textIsDisplayable && percent != 0 && style == STROKE){            canvas.drawText(percent + "%", centre - textWidth / 2, centre + textSize/2, paint); //画出进度百分比        //}        /**         * 画圆弧 ,画圆环的进度         */        //设置进度是实心还是空心        paint.setStrokeWidth(roundWidth); //设置圆环的宽度        paint.setColor(roundProgressColor);  //设置进度的颜色        RectF oval = new RectF(centre - radius, centre - radius, centre                + radius, centre + radius);  //用于定义的圆弧的形状和大小的界限        switch (style) {            case STROKE:{                paint.setStyle(Paint.Style.STROKE);                canvas.drawArc(oval, 0, 360 * progress / max, false, paint);  //根据进度画圆弧                break;            }            case FILL:{                paint.setStyle(Paint.Style.FILL_AND_STROKE);                if(progress !=0)                    canvas.drawArc(oval, 0, 360 * progress / max, true, paint);  //根据进度画圆弧                break;            }        }    }    public synchronized int getMax() {        return max;    }    /**     * 设置进度的最大值     * @param max     */    public synchronized void setMax(int max) {        if(max < 0){            throw new IllegalArgumentException("max not less than 0");        }        this.max = max;    }    /**     * 获取进度.需要同步     * @return     */    public synchronized int getProgress() {        return progress;    }    /**     * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步     * 刷新界面调用postInvalidate()能在非UI线程刷新     * @param progress     */    public synchronized void setProgress(int progress) {        if(progress < 0){            throw new IllegalArgumentException("progress not less than 0");        }        if(progress > max){            progress = max;        }        if(progress <= max){            this.progress = progress;            postInvalidate();        }    }    public int getCricleColor() {        return roundColor;    }    public void setCricleColor(int cricleColor) {        this.roundColor = cricleColor;    }    public int getCricleProgressColor() {        return roundProgressColor;    }    public void setCricleProgressColor(int cricleProgressColor) {        this.roundProgressColor = cricleProgressColor;    }    public int getTextColor() {        return textColor;    }    public void setTextColor(int textColor) {        this.textColor = textColor;    }    public float getTextSize() {        return textSize;    }    public void setTextSize(float textSize) {        this.textSize = textSize;    }    public float getRoundWidth() {        return roundWidth;    }    public void setRoundWidth(float roundWidth) {        this.roundWidth = roundWidth;    }}

xml

引用属性:

xmlns:android_custom="http://schemas.android.com/apk/res-auto"


<com.example.xx.zkmn1.RoundProgressBar        android:id="@+id/rpb"        android:layout_marginTop="40dp"        android:layout_gravity="center"        android:layout_width="180dip"        android:layout_height="180dip"        android:layout_marginBottom="78dp"        android_custom:roundColor="#D1D1D1"        android_custom:roundProgressColor="#0f0"        android_custom:roundWidth="10dip"        android_custom:textColor="#9A32CD"        android_custom:textIsDisplayable="false"        android_custom:textSize="18sp" />

改变进度Activity操作:

import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.Toast;public class MainActivity extends AppCompatActivity implements View.OnClickListener{    private RoundProgressBar rpb;    private Button btnSm;      @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //隐藏原有标题        getSupportActionBar().hide();        initView();        initListener();    }    private void initView() {        rpb = (RoundProgressBar) findViewById(R.id.rpb);        btnSm = (Button) findViewById(R.id.btn_sm);    }    private void initListener() {        btnSm.setOnClickListener(this);    }    Handler handler = new Handler(){        public static final int REQUEST_CODE =0 ;        @Override        public void handleMessage(Message msg) {            if(msg.what==1){                rpb.setProgress(rpb.getProgress()+1);            }else if(msg.what==2){                rpb.setProgress(0);            }        }    };    //扫描二微码按钮点击事件    @Override    public void onClick(View view) {        new Thread(){            @Override            public void run() {                while (true){                    if(rpb.getProgress()>=100){                        handler.sendEmptyMessage(2);                        break;                    }else{                        handler.sendEmptyMessage(1);                    }                    //每隔一秒发送一次handler                    try {                        sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }.start();    }}




原创粉丝点击