前几天写的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使用。