您的位置:首页 > 移动开发 > Android开发

Android读取系统控件的自定义属性

2017-02-25 21:09 405 查看
读取自定义属性

通常读取自定义控件的自定义属性是在自定义控件的构造函数中用context的obtainStyledAttributes方法获取TpyeArray对象,通过TpyeArray对象获取个自定义属性,最后别忘了recycle()。

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyViewGroup" >
<attr name="x_in" format="float"/>
<attr name="y_in" format="float"/>

</declare-styleable>
</resources>
自定义控件
public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array=context.obtainStyledAttributes(attrs,R.styleable.MyViewGroup);
x_in=array.getFloat(R.styleable.MyViewGroup_x_in,0);
y_in=array.getFloat(R.styleable.MyViewGroup_y_in,0);
array.recycle();
}

当系统控件中带有自定义属性如何读取?

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
vg:x_in="0.2"
vg:y_in="0.3"
/>

方法一:利用LayoutParams

当自定义控件是ViewGroup的子控件时且带有自定义属性的系统控件是其内,如下布局

 <com.znvoid.blogs.MyViewGroup
android:id="@+id/myview"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" vg:x_in="0.2" vg:y_in="0.3" />
</com.znvoid.blogs.MyViewGroup>


首先了解下generateLayoutParams()方法,为父容器生成
子view 的布局LayoutParams在Layoutinflater.rInflate()中被调用

public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}


如果一个View想要被添加到这个容器中,这个view可以调用此方法生成和容器类匹配的布局LayoutParams;
那么可以在自定义控件中重写generateLayoutParams()方法生成自定义的LayoutParams类对象从而达到读取自定义属性。

@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MyLayoutParams(getContext(), attrs);
}

class MyLayoutParams extends LayoutParams{
public float x_in;
public float y_in;

public MyLayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray array=c.obtainStyledAttributes(attrs,R.styleable.MyViewGroup);
x_in=array.getFloat(R.styleable.MyViewGroup_x_in,0);
y_in=array.getFloat(R.styleable.MyViewGroup_y_in,0);
//System.out.println("x_in"+x_in);
array.recycle();
}

}
方法二 LayoutInflater

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
app:x_in="1.2"
app:y_in="2.3"/>

</RelativeLayout>
先看LayoutInflater.inflate()源码

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}

final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");

//省略代码......

// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
//省略代码......
}}
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
boolean ignoreThemeAttr) {
//省略代码......
try { View view; if (mFactory2 != null) { view = mFactory2.onCreateView(parent, name, context, attrs); } else if (mFactory != null) { view = mFactory.onCreateView(name, context, attrs); } else { view = null; } if (view == null && mPrivateFactory != null) { view = mPrivateFactory.onCreateView(parent, name, context, attrs); }
//省略代码......       
}

通过源码看出LayoutInflater.inflate()方法会调用createViewFromTag()---->mFactory.onCreateView(name,context,attrs)

只要重写Factory.onCreateView()就能得到控件的AttributeSet属性对象

*
* 自定义布局加载器
*/

public class MyLayoutInflater extends LayoutInflater {

public MyLayoutInflater( Context newContext) {
super( newContext);

setFactory(new MyFatory());
}

public MyLayoutInflater(LayoutInflater original, Context newContext) {
super(original, newContext);
setFactory2(new MyFactory2());
}

@Override
public LayoutInflater cloneInContext(Context newContext) {
return new MyLayoutInflater(this, newContext);
}

public class MyFatory implements LayoutInflater.Factory {

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
return doCreateView(name,context,attrs);
}

//
}
public View doCreateView(String name, Context context, AttributeSet attrs) {
View view = null;
if (name.contains(".")) {//自定义控件生成
view = doCreateViewWithPackage(name, null, context, attrs);

} else {//系统控件的生成

if ((view = doCreateViewWithPackage(name, "android.view.", context, attrs)) == null)
view = doCreateViewWithPackage(name, "android.widget.", context, attrs);

}
if (view != null) {//自定义属性的读取
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyViewGroup);
float x_in = array.getFloat(R.styleable.MyViewGroup_x_in, 0);
float y_in = array.getFloat(R.styleable.MyViewGroup_y_in, 0);
System.out.println("x_in的值:" + x_in);

array.recycle();
}

return view;
}
private View doCreateViewWithPackage(String name, String prefix, Context context, AttributeSet attrs) {//根据控件名创建控件对象
try {
return MyLayoutInflater.this.createView(name, prefix, attrs);
} catch (ClassNotFoundException e) {
//e.printStackTrace();
}
return null;

}

class MyFactory2 implements Factory2 {

@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
return onCreateView(name,context,attrs);
}

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {

return doCreateView(name,context,attrs);
}

}

}
用自定义布局加载器去加载带有自定义属性的系统控件的布局就能读取其中的自定义属性
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 控件