关于自定义控件以及自定义属性的文章,可以查看 Android高手进阶教程(四)之----Android 中自定义属性(attr.xml,TypedArray)的使用!。本文主要在其基础之上结合实际开发当中遇到的问题,举例分析一下在使用TypedArray.getDimension时应当注意的问题。
主要显示代码main.xml关键代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:test="http://schemas.android.com/apk/res/com.yang" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/background"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="@string/shiyan"/> <com.yang.widget.TextViewAndSpaner android:layout_width="fill_parent" android:layout_height="wrap_content" test:item_content_text="@string/shiyan" test:item_content_textsize="18sp" test:item_content_textcolor="@android:color/black" test:item_option_prompt="@string/please_select" test:item_option_values="@array/tureorfalse" /> </LinearLayout>text_spaner_view.xml代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1.33" android:orientation="vertical" > <TextView android:id="@+id/item_content" android:layout_width="240dip" android:layout_height="wrap_content" android:singleLine="false" android:textSize="15sp" /> <TextView android:id="@+id/item_remark_str" android:layout_width="240dip" android:layout_height="wrap_content" android:singleLine="false" android:textSize="10sp" android:visibility="gone"/> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="vertical" > <Button android:id="@+id/item_option" android:layout_width="80dip" android:layout_height="45dip" android:text="@string/please_select" android:textSize="13sp" /> <TextView android:id="@+id/item_option_ps" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="false" android:textSize="10sp" android:layout_gravity="center" android:visibility="gone" /> <Button android:id="@+id/item_remark" android:layout_width="80dip" android:layout_height="30dip" android:text="备注" android:textSize="10sp" android:visibility="gone" /> </LinearLayout> </LinearLayout> <View android:layout_width="fill_parent" android:layout_height="1dp" android:background="@android:color/white" /> </LinearLayout>TextViewAndSpaner.java
package com.yang.widget; import com.yang.R; import com.yang.utils.Logger; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; public class TextViewAndSpaner extends LinearLayout { private TextView item_content; private Button item_remark; // 1、使用startActivityforResult或者 // 2、设置Intent的Type属性 // 但是使用后者时需要将原先的Activity传过来,在TextViewAndSpaner中添加代码。 // 同时,要开启Activity当中设置判断条件。开发复杂。因此使用前者。 private TextView item_remark_str; private Button item_option; public Button getItem_option() { return item_option; } public void setItem_option(Button item_option) { this.item_option = item_option; } private TextView item_option_ps; private Context mContext; private boolean isopposites; /** * 默认构造函数 */ public TextViewAndSpaner(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub mContext = context; LayoutInflater.from(context).inflate(R.layout.text_spaner_view, this, true); item_content = (TextView) findViewById(R.id.item_content); item_remark = (Button) findViewById(R.id.item_remark); item_option = (Button) findViewById(R.id.item_option); item_remark_str = (TextView) findViewById(R.id.item_remark_str); item_option_ps = (TextView) findViewById(R.id.item_option_ps); TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.TextViewAndSpaner); setItemContext(typeArray); setItemRemark(typeArray); // 设置相关的点击选项 setOption(typeArray); setRemark(typeArray); // 回收 typeArray.recycle(); } private void setRemark(TypedArray typeArray) { // TODO Auto-generated method stub boolean remarkFlag = typeArray.getBoolean( R.styleable.TextViewAndSpaner_is_remark_enable, false); if (remarkFlag) { item_remark.setVisibility(View.VISIBLE); item_remark.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub remarkDialog(); } }); } } private void setItemContext(TypedArray typeArray) { int contentColor = typeArray.getColor( R.styleable.TextViewAndSpaner_item_content_textcolor, 0XFFFFFFFF); item_content.setTextColor(contentColor); Logger.d("getDimensionPixelOffset" + typeArray .getDimensionPixelOffset( R.styleable.TextViewAndSpaner_item_content_textsize, 15)); Logger.d("getDimensionPixelSize" + typeArray .getDimensionPixelSize( R.styleable.TextViewAndSpaner_item_content_textsize, 15)); Logger.d("getLayoutDimension" + typeArray .getLayoutDimension( R.styleable.TextViewAndSpaner_item_content_textsize, 15)); float contentSize = typeArray.getDimension( R.styleable.TextViewAndSpaner_item_content_textsize, 15); Logger.d("contentSize is " + contentSize); item_content.setTextSize(TypedValue.COMPLEX_UNIT_SP, contentSize); String contentStr = typeArray .getString(R.styleable.TextViewAndSpaner_item_content_text); item_content.setText(contentStr); } private void setItemRemark(TypedArray typeArray) { boolean remarkFlag = typeArray.getBoolean( R.styleable.TextViewAndSpaner_is_remark_enable, false); if (remarkFlag) { int remarkColor = typeArray.getColor( R.styleable.TextViewAndSpaner_item_remark_textcolor, 0XFFFFFFFF); item_remark_str.setTextColor(remarkColor); float remarkSize = typeArray.getDimension( R.styleable.TextViewAndSpaner_item_remark_textsize, 12); item_remark_str.setTextSize(remarkSize); } } private void setOption(TypedArray typeArray) { isopposites = typeArray.getBoolean( R.styleable.TextViewAndSpaner_is_item_option_opposites, false); boolean isResult = typeArray.getBoolean( R.styleable.TextViewAndSpaner_is_query_result, false); if (isResult) item_option.setEnabled(false); else { final CharSequence[] values = typeArray .getTextArray(R.styleable.TextViewAndSpaner_item_option_values); final String when_to_show_dialogue_item = typeArray .getString(R.styleable.TextViewAndSpaner_when_to_show_dialogue_item); final String prompt = typeArray .getString(R.styleable.TextViewAndSpaner_item_option_prompt); final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>( mContext, android.R.layout.simple_spinner_dropdown_item, values); final CharSequence[] attrs = typeArray .getTextArray(R.styleable.TextViewAndSpaner_item_option_selected_dialogue_item); final String promptStr = typeArray .getString(R.styleable.TextViewAndSpaner_prompt_of_dialog); item_option.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub new AlertDialog.Builder(mContext) .setTitle(prompt) .setAdapter(adapter, new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int which) { String selectedValue = values[which] .toString(); item_option.setText(values[which]); if (selectedValue .equals(when_to_show_dialogue_item)) { showDiag(attrs, promptStr); } else { item_option_ps.setText(null); item_option_ps .setVisibility(View.GONE); } dialog.dismiss(); } }).create().show(); } }); } } private void showDiag(final CharSequence[] attrs, String promptStr) { AlertDialog.Builder builder = new Builder(mContext); builder.setTitle("请选择……"); builder.setPositiveButton(attrs[0], new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub item_option_ps.setVisibility(View.VISIBLE); item_option_ps.setText(attrs[0]); } }); builder.setNegativeButton(attrs[1], new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub item_option_ps.setVisibility(View.VISIBLE); item_option_ps.setText(attrs[1]); } }); builder.setIcon(android.R.drawable.ic_dialog_info); builder.setMessage(promptStr); builder.show(); } private void remarkDialog() { final EditText remark_text = new EditText(mContext); String oldRemark_text = (String) item_remark_str.getText(); if (!TextUtils.isEmpty(oldRemark_text)) { remark_text.setText(oldRemark_text); } new AlertDialog.Builder(mContext).setTitle("添加备注") .setIcon(android.R.drawable.ic_dialog_info) .setView(remark_text) .setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub item_remark_str.setVisibility(View.VISIBLE); item_remark_str.setText(remark_text.getText() .toString().trim()); } }).setNegativeButton("取消", null).show(); } public String getKeyValue() { String optionResult = (String) item_option.getText(); if (isopposites) { // 如果是反义,则在值后面加空格 return optionResult + " "; } return optionResult; } public void setOptionDefaultValue() { item_option.setText(""); } public String getRemarkValue() { String psStr = (String) item_option_ps.getText(); String remarkStr = (String) item_remark_str.getText(); if (psStr != null && remarkStr != null && !TextUtils.isEmpty(psStr.trim()) && !TextUtils.isEmpty(remarkStr.trim())) { return item_content.getText() + "的备注:" + psStr + "," + remarkStr; } if (psStr != null && !TextUtils.isEmpty(psStr.trim())) { return item_content.getText() + "的备注:" + psStr; } if (remarkStr != null && !TextUtils.isEmpty(remarkStr.trim())) { return item_content.getText() + "的备注:" + remarkStr; } return null; } }MainActivity.java
package com.yang; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
例子图示如下:
摩托罗拉xt910
中兴 v880
中兴 n760
华为c8500
我们看到根据屏幕大小的不同,两行文字中下行文字的大小也随之改变,其中摩托罗拉xt910和中兴 v880下面字体的都比上面字体大,而中兴 n760下面字体与上面字体大小是相同的,而华为c8500下面字体比上面字体小。我们再来看看main.xml代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:test="http://schemas.android.com/apk/res/com.yang" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/background"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="@string/shiyan"/> <com.yang.widget.TextViewAndSpaner android:layout_width="fill_parent" android:layout_height="wrap_content" test:item_content_text="@string/shiyan" test:item_content_textsize="18sp" test:item_content_textcolor="@android:color/black" test:item_option_prompt="@string/please_select" test:item_option_values="@array/tureorfalse" /> </LinearLayout>TextView设置的字体大小为18sp,而com.yang.widget.TextViewAndSpaner设置的字体大小也为18sp
com.yang.widget.TextViewAndSpaner读取字体大小的代码如下:
float contentSize = typeArray.getDimension( R.styleable.TextViewAndSpaner_item_content_textsize, 15); Logger.d("contentSize is " + contentSize);
四个手机打印出自定义属性来的字体大小为:
摩托罗拉xt910 09-08 15:07:00.685: D/CustomWidget(4937): contentSize is 27.0 中兴 v880 09-08 15:15:04.685: D/CustomWidget(4937): contentSize is 27.0 中兴 n760 09-08 15:05:15.640: D/CustomWidget(31487): contentSize is 18.0 华为c8500 09-08 15:22:48.565: D/CustomWidget(2018): contentSize is 13.5
以上我们看到使用自定义属性的
typeArray.getDimension
是不靠谱的,字体的大小会根据不同屏幕的分辨率大小而改变字体的大小。我们再来看看关于getDimension
Retrieve a dimensional for a particular resource ID. Unit conversions are based on the current DisplayMetrics
associated with the resources.
id | The desired resource identifier, as generated by the aapt tool. This integer encodes the package, type, and resource entry. The value 0 is an invalid identifier. |
---|
Resources.NotFoundException | Throws NotFoundException if the given ID does not exist. |
---|
getDimensionPixelOffset(int)
getDimensionPixelSize(int)
单位的转换是基于当前资源显示分比率的。
因此我们要慎重使用getDimension定义的属性,不然我们的应用部署到不同的应用上,原先非常美丽的效果,会变得面目全非。
使用时,默认将字体大小设定好,而在xml配置文件当中删除关于字体大小的设置。如
删除main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:test="http://schemas.android.com/apk/res/com.yang" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/background"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="@string/shiyan"/> <com.yang.widget.TextViewAndSpaner android:layout_width="fill_parent" android:layout_height="wrap_content" test:item_content_text="@string/shiyan" test:item_content_textsize="18sp" test:item_content_textcolor="@android:color/black" test:item_option_prompt="@string/please_select" test:item_option_values="@array/tureorfalse" /> </LinearLayout>中的
test:item_content_textsize="18sp"配置,使其变成:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:test="http://schemas.android.com/apk/res/com.yang" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/background"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="@string/shiyan"/> <com.yang.widget.TextViewAndSpaner android:layout_width="fill_parent" android:layout_height="wrap_content" test:item_content_text="@string/shiyan" test:item_content_textcolor="@android:color/black" test:item_option_prompt="@string/please_select" test:item_option_values="@array/tureorfalse" /> </LinearLayout>
同时在读取自定义属性的java代码中设置好自己想要的字体大小即可,如下:
float contentSize = typeArray.getDimension( R.styleable.TextViewAndSpaner_item_content_textsize, 15);