自定义的View练习

部分资料  来自安卓群英传  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();

来获取自定义属性

实现效果




二\实现一个自定义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>

实现效果



<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>


猜你喜欢

转载自blog.csdn.net/rungby/article/details/80901492