android自定义实例化,Android自定义View构造函数分析

android开发中也都遇到过自定义View,第一步肯定是添加构造函数吧,那构造函数到底负责什么哪些方面的职责呢。第一个想到的应该是自定义View中需要设置的属性,没错这也是构造函数的重要职责之一。接下来我们就一起看看自定义View构造函数的一二三吧。

public class CustomView extends View {

private final static String TAG = CustomView.class.getSimpleName();

/**

* 在Java代码中直接new一个CustomView实例的时候,会调用该构造函数

* @param context

*/

public CustomView(Context context) {

this(context,null);

}

/**

* 在xml中引用CustomView标签的时候,会调用2参数的构造函数。

* 这种方式通常是我们需要自定义View的属性的时候,使用2参数的构造函数。

*/

public CustomView(Context context, AttributeSet attrs) {

this(context, attrs,0);

}

/**

* 3个参数的构造函数一般是由我们主动调用的,如:上面2个参数的构造函数调用。

*/

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

super(context, attrs, defStyleAttr);

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomView);

if (ta!=null){

String attr1 = ta.getString(R.styleable.CustomView_attr1);

String attr2 = ta.getString(R.styleable.CustomView_attr2);

String attr3 = ta.getString(R.styleable.CustomView_attr3);

String attr4 = ta.getString(R.styleable.CustomView_attr4);

Log.i(TAG, "attr1=" + attr1);

Log.i(TAG, "attr2=" + attr2);

Log.i(TAG, "attr3=" + attr3);

Log.i(TAG, "attr4=" + attr4);

ta.recycle();

}

}

}

主要看obtainStyledAttributes方法,跟进去看

public final TypedArray obtainStyledAttributes(

AttributeSet set, @StyleableRes int[] attrs) {

return getTheme().obtainStyledAttributes(set, attrs, 0, 0);

}

继续跟进,很快就可以找到最终实现

TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,

AttributeSet set,

@StyleableRes int[] attrs,

@AttrRes int defStyleAttr,

@StyleRes int defStyleRes) {

synchronized (mKey) {

final int len = attrs.length;

final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);

// XXX note that for now we only work with compiled XML files.

// To support generic XML files we will need to manually parse

// out the attributes from the XML file (applying type information

// contained in the resources and such).

final XmlBlock.Parser parser = (XmlBlock.Parser) set;

AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,

parser != null ? parser.mParseState : 0,

attrs, array.mData, array.mIndices);

array.mTheme = wrapper;

array.mXml = parser;

return array;

}

}

解释一下几个参数

AttributeSet set:属性值得集合;

int[] attr:自定义属性在R类中自动生成的int型的数组,数组中包含自定义属性的资源ID;

int defStyleAttr:当前Theme中包含的一个指向style的引用,当我们没有给自定义View设置declare-styleable值的时候,默认从该集合中查找布局文件中配置的属性值。传入0表示不向该defStyleAttr中查找默认值;

int defStyleRes:指向一个Style的资源ID,但只在defStyleAttr为0或者Theme中没有为defStyleAttr属性赋值的时候起作用。

先说结论:

View中自定义的属性值可以通过很多种方式来进行赋值,不同的赋值方式中存在一个优先级的问题;举个例子,通过A方式和B方式对属性attribute_1进行赋值,如果A的优先级高于B,则A方式赋值后再B方式赋值,B方式所赋的值无法覆盖A方式的赋值,反正却可以。

属性赋值优先级:

xml中CustomView标签下直接赋值 > xml中CustomView标签下通过引用style进行赋值 > CustomView所在的Activity的Theme中指定style进行赋值 > 用构造函数中defStyleRes指定的默认值进行赋值

不明白,没关系,下面会通过现象来证明以上结论。

为了更好进行比较,我将所有的属性的类型定义为String字符型,

path:/res/values/attr_custom_view.xml

说明一下,declare-styleable标签只是为了方便attr的使用,attr不依赖与declare-styleable;也就是说你完全可以直接在resources中直接使用attr。定义一个attr就会在R类中生成一个该属性对应的ID,而通过在declare-styleable定义一组attr,就会在R类中生成一个该组属性对应的ID属性。

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomView);

或者

int[] costomAttrs = {R.attr.attr1,R.attr.attr2,R.attr.attr3,R.attr.attr4};

TypedArray ta = context.obtainStyledAttributes(attrs, costomAttrs);

所以说declare-styleable标签只是为了方便attr的使用,在obtainStyledAttributes方法中传入的参数都是一个属性的资源ID数组,所以只要能取到属性的资源ID,怎么做都是可以的。

接下来就开始赋值和取属性值了:

第一个参数和第二个参数

直接在xml中赋值和在style引用中进行赋值做比较:

src/main/res/layout/activity_main.xml

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

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

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context="com.itcodecook.viewconstructor.MainActivity">

android:layout_width="match_parent"

android:layout_height="300dp"

app:attr1="value_attr1"

style="@style/CustomViewStyle"/>

src/main/res/values/styles.xml

value_attr1_from_style

value_attr2_from_style

public CustomView(Context context, AttributeSet attrs) {

this(context, attrs,0);}

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

super(context, attrs, defStyleAttr);

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomView);

if (ta!=null){

String attr1 = ta.getString(R.styleable.CustomView_attr1);

String attr2 = ta.getString(R.styleable.CustomView_attr2);

String attr3 = ta.getString(R.styleable.CustomView_attr3);

String attr4 = ta.getString(R.styleable.CustomView_attr4);

Log.i(TAG, "attr1=" + attr1);

Log.i(TAG, "attr2=" + attr2);

Log.i(TAG, "attr3=" + attr3);

Log.i(TAG, "attr4=" + attr4);

ta.recycle();

}

}

执行结果:

b65ce8e7a23a

执行结果

显而易见,xml中直接对属性进行赋值的优先级高于在style引用中的赋值。

第三个参数defStyleAttr

上文也有说到View的三参数构造函数是手动调用的,在通过xml中标签的形式实例化View系统是调用2个参数的构造函数的。从上文的代码中也可以看到是由两参数的构造函数去调用三参数的构造函数,只不过第三个参数传0。

从字面上理解,defStyleAttr表示默认的style,对它进行赋值的优势在于可以统一样式。

1,在res/values/attr_custom_view.xml中定义一个attr5,attr5是一个引用类型;

2,找到CustomView所在的Activity或者Application的theme属性,如果Activity有就用Activity的theme,没有就用Application的theme,然后再Activity的Theme中给attr5赋值;

3,在CustomView中调三参数的构造方法中传入第三个参数:R.attr.attr5。

src/main/AndroidManifest.xml:

android:theme="@style/AppTheme">

···

src/main/res/values/styles.xml:

@style/CustomViewAttr5Value

value_attr1_from_defStyleAttr

value_attr2_from_defStyleAttr

value_attr3_from_defStyleAttr

//2个参数的构造函数中调用3参数的构造函数时,需传入默认的取值

public CustomView(Context context, AttributeSet attrs) {

this(context,attrs,R.attr.attr5);}

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

super(context, attrs, defStyleAttr);

TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomView,defStyleAttr,0);

···

}

执行结果:

b65ce8e7a23a

执行结果

第四个参数defStyleAttr

前面也说过,只有当第三个参数为0的时候或者Theme没有为第三个参数赋值的时候,它才有效;

在src/main/res/values/styles.xml中添加:

src/main/res/values/styles.xml:

value_attr1_from_defStyleRes

value_attr2_from_defStyleRes

value_attr3_from_defStyleRes

value_attr4_from_defStyleRes

在代码中传入:

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

super(context, attrs, defStyleAttr);

TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomView,defStyleAttr,

R.style.CustomViewDefStyleRes);

···

}

执行结果:

b65ce8e7a23a

执行结果

修改,将第三个参数传入0,即不使用默认的style。

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

super(context, attrs, defStyleAttr);

TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomView,0,

R.style.CustomViewDefStyleRes);

···

}

执行结果:

b65ce8e7a23a

执行结果

修改,或者将src/main/res/values/styles.xml中的attr5注释掉:

src/main/res/values/styles.xml:

执行结果:

b65ce8e7a23a

执行结果

由此可见,以上结论的正确性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在Android上自定义半圆形进度条,可以按照以下步骤进行: 1. 首先,在XML布局文件中添加一个半圆形的View。可以使用自定义View继承自View类,或者使用现有的绘图类如Canvas和Path来绘制半圆形。 2. 在自定义View中,重写onDraw方法,通过Canvas对象绘制半圆形。可以使用drawArc方法来画出一个弧线,指定起点、终点和角度,来绘制半圆形。 3. 在自定义View中添加一个属性来表示当前进度。可以使用属性动画或者定时器来不断更新进度,并调用invalidate方法来重绘View。 4. 在自定义View中添加一些自定义属性,如颜色、宽度等,来实现进度条的样式定制。 5. 在Activity中使用这个自定义View,可以通过findViewById找到它,并设置进度条的属性和监听器等。 通过以上步骤,就可以实现一个自定义的半圆形进度条。根据具体需求和设计,可以进行更多的样式和功能定制,如添加文本显示、动画效果等。 ### 回答2: 要实现Android定义半圆形进度条,可以采用以下步骤: 1. 首先,在布局文件中创建一个自定义View,用于绘制半圆形进度条。可以使用Canvas来进行绘制。在View构造函数中初始一些必要的参数,如进度条的颜色、背景颜色等。 2. 在自定义View的onDraw()方法中,使用Canvas绘制一个半圆形的背景,可以使用drawArc()方法,并设置起始角度和扫描角度。 3. 接着,绘制进度条的一段弧线。根据进度的值计算出起始和结束的角度,并使用drawArc()方法进行绘制。 4. 在Activity中,实例定义View,并将其添加到布局中。可以使用setProgress()方法来设置进度条的进度值。 5. 如果需要实现动画效果,可以使用ValueAnimator来改变进度值,并在动画过程中不断调用invalidate()方法来刷新视图。 总结:自定义半圆形进度条的关键是使用Canvas的drawArc()方法进行绘制,根据进度值来计算起始和结束的角度,并使用invalidate()方法来进行视图的刷新。通过这些步骤,即可实现Android定义半圆形进度条的效果。 ### 回答3: 要实现Android定义半圆形进度条,可以通过自定义View来实现。 首先,创建一个继承自View的自定义View类,并重写其中的三个方法:onMeasure()、onDraw()和onSizeChanged()。 在onMeasure()方法中,设置View的宽度和高度,可以根据需求来设置,比如设置为200dp,然后将测量的结果保存。 在onSizeChanged()方法中,获取View的宽度和高度,用于后续计算绘制进度条的位置。 在onDraw()方法中,绘制半圆形进度条的背景和进度。首先,使用Paint类创建两个画笔,一个用于绘制背景,一个用于绘制进度。然后,通过Path类创建一个半圆形的路径,使用drawPath()方法绘制出半圆形。接着,根据进度计算出进度条的结束位置,使用drawArc()方法绘制出进度条。最后,使用drawText()方法绘制出进度的文字。 在Activity或Fragment中使用自定义View,可以通过布局文件或代码的方式进行添加。如果使用布局文件,可以在XML文件中使用自定义的命名空间,并设置View的属性。如果使用代码,可以在onCreate()方法中使用addView()方法添加。 以上就是实现Android定义半圆形进度条的大致步骤。根据具体需求,还可以添加其他功能,比如添加动画效果,改变进度条的颜色等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值