欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义的View练习

程序员文章站 2022-05-30 20:08:11
...

部分资料  来自安卓群英传  https://blog.csdn.net/a120705230/article/details/51970864

部分资料来自于在那桌开发艺术探索

一\实现一个简单的自定义View---画一个圆

public class Circle extends View {


//画笔颜色
    private int mColor;
//新建画笔,Paint.ANTI_ALIAS_FLAG,表示抗锯齿
    private Paint mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
//View的最小宽度和高度
    private int mWidth;
    private int mHeight;

//构造器,分两类,一个是默认构造器,一类是带属性的构造器,第二类构造器通过重载,都指向Circle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) 
    public Circle(Context context) {
        super(context);
        init();
    }

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

    public Circle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
//获取View的颜色
        TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.Circle);
        mColor=a.getColor(R.styleable.Circle_circle_color, Color.RED);
        a.recycle();
//初始化画笔颜色跟最小宽度高度
        init();
    }

 private void init() {
        mPaint.setColor(mColor);
        mWidth=100;
        mHeight=100;

    }



//MeasureSpec.AT_MOST  wrap_content
//MeasureSpec.EXACTLY  match_parent
//自定义View,需要对wrap和match做区分,默认的实现,wrap等同于match
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthSpecMod=MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize=MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMod=MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize=MeasureSpec.getSize(heightMeasureSpec);

//如果是宽度高度都为wrap,那么设置测量的宽度高度为mWidth和mHeight
        if (widthSpecMod==MeasureSpec.AT_MOST&&heightSpecMod==MeasureSpec.AT_MOST){
            setMeasuredDimension(mWidth,mHeight);
        }else if (widthSpecMod==MeasureSpec.AT_MOST){
            setMeasuredDimension(mWidth,heightSpecSize);
        }else if (heightSpecMod==MeasureSpec.AT_MOST){
            setMeasuredDimension(widthSpecSize,mHeight);
        }
    }

   
//半径是宽度和高度最小值的一半,圆心,x在左padding加半径,y在顶部padding加半径.
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int paddingl=getPaddingLeft();
        int paddingr=getPaddingRight();
        int paddingt=getPaddingTop();
        int paddingb=getPaddingBottom();
        int width=getWidth()-paddingl-paddingr;
        int height=getHeight()-paddingt-paddingb;
        int Radius=Math.min(width,height)/2;
        canvas.drawCircle(paddingl+width/2,paddingt+height/2,Radius,mPaint);
    }
}

attrs自定义属性文件

位置在value文件夹下,一般取名风格,attrs_circle.xml

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

在构造器中通过

TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.Circle);
        mColor=a.getColor(R.styleable.Circle_circle_color, Color.RED);

        a.recycle();

来获取自定义属性

实现效果

自定义的View练习自定义的View练习



二\实现一个自定义ViewGroup

简单的实现效果

让两个textView并列排放

public class TextViewNest extends ViewGroup{


    //最小宽度高度
    private int mWidth;
    private int mHeight;
    //子View之间的间距
    private float mMargin=8* getContext().getResources().getDisplayMetrics().density;

    //构造方法,同自定义View
    public TextViewNest(Context context) {
        super(context);
        init();
    }


    public TextViewNest(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }


    public TextViewNest(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.TextViewNest);
        mMargin=a.getDimension(R.styleable.TextViewNest_m_margin,0);
        a.recycle();
        init();
    }


    //初始化最小宽度高度
    private void init() {
        mWidth=100;
        mHeight=100;

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取ViewGroup的测量模式和测量长度
        int widthSpecMod=MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize=MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMod=MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize=MeasureSpec.getSize(heightMeasureSpec);
//累计最大宽度,初始值为ViewGoup的左右padding值
        int  maxWidth=getPaddingLeft()+getPaddingRight();
//累计最大高度,初始值为ViewGroup的上下padding值
        int maxHeight=getPaddingTop()+getPaddingBottom();

//首先测量每一个childView
        for (int i=0;i<getChildCount();i++) {
            View childView = getChildAt(i);
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);
        }

//当内部没有childView的时候,设置ViewGroup宽高为最小值
        if (getChildCount()==0){
            setMeasuredDimension(mWidth,mHeight);

//当宽高为wrap模式时,获取每一个childView的测量值,高度,高度为上下padding值加子View高度的最大值.宽度为左右padding加上所有子View的宽度,宽度不小于最小宽度,高度不小于最小高度
        }else if (widthSpecMod==MeasureSpec.AT_MOST&&heightSpecMod==MeasureSpec.AT_MOST){
            for (int i=0;i<getChildCount();i++){
                View childView=getChildAt(i);
                maxHeight=Math.max(maxHeight,getPaddingTop()+getPaddingBottom()+childView.getMeasuredHeight());
                maxWidth+=childView.getMeasuredWidth();
            }
//把子View之间的间距值mMargin加上
            maxWidth+=mMargin*(getChildCount()-1);
            setMeasuredDimension(Math.max(mWidth,maxWidth),Math.max(mHeight,maxHeight));
           
//当宽度为wrap模式时,设置高度为ViewGroup的测量值,宽度,为左右padding加上所有内部View的宽度值,宽度不小于最小宽度
        }else if (widthSpecMod==MeasureSpec.AT_MOST){
            for (int i=0;i<getChildCount();i++){
                View childView=getChildAt(i);
                maxWidth+=childView.getMeasuredWidth();
            }
            maxWidth+=mMargin*(getChildCount()-1);
            setMeasuredDimension(Math.max(mWidth,maxWidth),heightSpecSize);

//当高度为wrap模式时,宽度设置为ViewGroup的测量值,高度设置为上下padding内部View高度的最大值,高度不小于最小高度
        }else if (heightSpecMod==MeasureSpec.AT_MOST) {
            for (int i = 0; i < getChildCount(); i++) {
                View childView = getChildAt(i);
                maxHeight = Math.max(maxHeight, getPaddingTop() + getPaddingBottom() + childView.getMeasuredHeight());
            }
            setMeasuredDimension(widthSpecSize, Math.max(mHeight, maxHeight));
        }
    }



    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
        int paddingl=getPaddingLeft();
        int paddingr=getPaddingRight();
        int paddingt=getPaddingTop();
        int paddingb=getPaddingBottom();

        int mChildCount=getChildCount();
//起始点的x坐标
        int mLeft=paddingl;
//起始点的y坐标
        int mTop=paddingt;
//当子View可见的时候,计算子View的宽高,起始点一支,右下角终点由起点坐标加上自身宽高得到.同时,起点x要平移width,得到下个View的起点
        for (int n =0;n<mChildCount;n++){
            View childView=getChildAt(n);
            if (childView.getVisibility()!=GONE){
                int width=childView.getMeasuredWidth();
                int height=childView.getMeasuredHeight();
                childView.layout(mLeft,mTop,width+mLeft,height+mTop);
                mLeft+=width;
                if (n!=mChildCount-1){
                    mLeft+=mMargin;
                }
            }
        }

    }
}

自定义属性

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

    <declare-styleable name="TextViewNest">
        <attr name="m_margin" format="dimension"/>
    </declare-styleable>
</resources>

实现效果

自定义的View练习


<com.example.mycanlendartest.TextViewNest
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:padding="30dp"
        app:m_margin="10dp"
        android:background="@android:color/holo_blue_light"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我是1"
            android:textSize="14sp"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我是2"
            android:textSize="14sp"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我是3"
            android:textSize="14sp"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我是4"
            android:textSize="14sp"/>
    </com.example.mycanlendartest.TextViewNest>


相关标签: 自定义View