res排气auto怎么设置自定义view(再回首)

新闻资讯2026-04-21 00:35:24

前几天写的demo没法自己实现在xml声明使用,而是把radius之类的写死了。这样很不方便。

于是继续改进。 栋哥推荐的书的作者,刚神 果然非常厉害。

首先 需要对ondraw方法重写一下。

  @Override
    protected void onDraw(Canvas canvas) 

这样就可以完成自定义长宽高了,并且半径自动适应。

其实这时候我们还可以进一步完善,给他们提供attr 就是我们自定义的属性。什么是自定义的属性?比如我们用android:layout_width,其实就是android系统给我们提供的。注意 ,如果我们要使用自定义属性 请在布局代码中加入;

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

例如:

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


这里的xmlns:android=“http://schemas.android.com/apk/res/android” 就是自动扫描android给我们提供的默认属性。

第一步 在values目录下 创建xml文件,记住要以attrs开头

<?xml version="1.0" encoding="utf-8" ?>
<resources>
    <declare-styleable name="CustomView">
     <!--->attr name是我们自己定义的名字,format是android给我们提供的格式 可以搜一下<!-->
        <attr name="circle_color" format="color"></attr>
        <!--->照虎画🐱  自己定一个属性试一下<!-->
        <attr name="circle_style" format="float"></attr>
    </declare-styleable>


</resources>

这样就ok的设置了自定义的属性。

接下来就是我们view控件里的操作了,比如这里。先声明;

    private int mColor  ;
    private float mStrokeWidth;

接着我们就要取出在布局中定义的属性,若没有定义,我们应该默认一个。

    public CustomView(Context context,AttributeSet attrs,int defStyleAttr)

ok,基本大功告成,在init的时候对画笔什么的进行相关设置即可。贴上完整的view代码。

package com.example.testviewgroup;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class CustomView extends View {
    private Paint mPaint;// 画笔
    private int mColor  ;
    private float mStrokeWidth;

    public CustomView(Context context) {

        this(context, null);
        // 初始化画笔
        initPaint();
    }


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

    }

    public CustomView(Context context,AttributeSet attrs,int defStyleAttr)

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

    }

    /**
     * 初始化画笔
     */
    private void initPaint() 

    @Override
    protected void onDraw(Canvas canvas) }

我们定义了一个圆环,提供了两个自定义属性,分别是颜色和秒边宽度,若不定义,默认为红色和20.

👌

这个时候问题又来了,根据绘制源码知道,若不对onMeasure加以处理,在对自定义view设置wrap_content时,会等于父控件的大小,就等于math_parent, 显然是不对的。

所以对onMeasure进行重写。

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        else if(widthMeasureSpec ==MeasureSpec.AT_MOST)
        else if(heightSpecMode == MeasureSpec.AT_MOST)


    }

上述代码是的200是我们默认设置的(AT_MOST下的自定义宽度,关于MeasureSpec,您可以自行搜索,这里推荐一本书《android开发艺术探索》),你也可以自己设置它。

-------------分割线----------------

但是问题又来了,我们要考虑用户使用,这是一个圆。当用户设定宽/高其中一个为 确切的 值,另一个为wrap_content时候,我们显然应该是将其中一个设定的为圆。并且处理一下我们圆的线宽,以免不能完整显示。故再次修改一下,完整代码如下

package com.example.testviewgroup;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class CustomView extends View {
    private Paint mPaint;// 画笔
    private int mColor;
    private float mStrokeWidth;

    public CustomView(Context context) {

        this(context, null);
        // 初始化画笔

    }


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

    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) 

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  else if (widthMeasureSpec == MeasureSpec.AT_MOST)  else if (heightSpecMode == MeasureSpec.AT_MOST) 


    }

    /**
     * 初始化画笔
     */
    private void initPaint() 


    @Override
    protected void onDraw(Canvas canvas) 


}


然后我们可以提供一些优先级之类的属性,这个自己去做就好了,要搭配自定义的ViewGroup使用。