在开发项目工程中,有时候系统的一下控件即View无法满足我们的需求,此时就需要自定义View
在这里,我们举一个简单的自定义View的小例子
需求:如下图,自定义一个View 并显示在ListView上
其中ListView每个字条目都是自定义的一个View(包括一个ImageView 两个TextView 和一个CheckBox)
以往我们用的View都是系统的,此时呢,我们用自定义View 并显示在ListView上
下面,我们直接上代码(以下"MyView" 指自定义View)
1.写一个类MyView继承 RelativeLayout,来完成自定义View的第一步
package cn.cbd.myview; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; //新建一个类 继承RelativeLayout public class MyView extends RelativeLayout { private CheckBox cb_myview_item; private TextView tv_myview_item_age; private TextView tv_myview_item_name; private ImageView iv_myview_icon; public MyView(Context context, AttributeSet attrs) { super(context, attrs); //获取布局加载器LayoutInflater对象 LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); //把一个xml文件转换成一个view View view = inflater.inflate(R.layout.myview, this); //找到相应的控件 cb_myview_item = (CheckBox) view.findViewById(R.id.cb_myview_item); tv_myview_item_age=(TextView) view.findViewById(R.id.tv_myview_item_age); tv_myview_item_name=(TextView) view.findViewById(R.id.tv_myview_item_name); iv_myview_icon = (ImageView) view.findViewById(R.id.iv_myview_icon); //为自定义的my_view设置两个属性值name和 age TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.my_view); //从TypedArray数组中获取要设置的属性值name和age String name = array.getString(R.styleable.my_view_name); String age = array.getString(R.styleable.my_view_age); //为自定义控件上两个TextView对象设置值 tv_myview_item_name.setText(name); tv_myview_item_age.setText(age); } /** * 判断自定义控件上的CheckBox是否被点击 * @return true 代表被点击 false 表示没有被点击 */ public boolean isChecked() { return cb_myview_item.isChecked(); } /** * 设置自定义控件上的CheckBox选中状态 * @param isChecked true 表示选中 false未选中 */ public void setIsChecked(boolean isChecked) { cb_myview_item.setChecked(isChecked); } /** * 设置名字 * @param name */ public void setName(String name) { tv_myview_item_name.setText(name); } /** * 设置年龄 * @param name */ public void setAge(int age) { tv_myview_item_age.setText(age); } /** * 设置头像 * @param drawable */ public void setImage(Drawable drawable) { iv_myview_icon.setImageDrawable(drawable); } }
上面我们看到在为自定义的my_view设置两个属性值name和 age的时候会用到一个R.styleable.my_view这样一个集合对象
这个是怎么来的呢,这个是我们需要在values目录下创建一个xxx.xml文件,来存放自定义View上的两个TextView上的name和age属性值
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="my_view"> <attr name="name" format="string" /> <attr name="age" format="string" /> </declare-styleable> </resources>
到现在为止呢,我们的自定义View控件对象已经写好,接下来就是怎么运用自定义控件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:andjoyo="http://schemas.android.com/apk/res/cn.cbd.myview" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <cn.cbd.myview.myview_item android:id="@+id/myView" android:layout_width="fill_parent" android:layout_height="wrap_content" andjoyo:name = "小王" andjoyo:age = "20"> </cn.cbd.myview.myview_item> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:andjoyo="http://schemas.android.com/apk/res/cn.cbd.myview"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<cn.cbd.myview.myview_item
android:id="@+id/myView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
andjoyo:name = "小王"
andjoyo:age = "20">
</cn.cbd.myview.myview_item>
</LinearLayout>
上面红色字体是需要我们自己添加上去的
xmlns:andjoyo="http://schemas.android.com/apk/res/cn.cbd.myview" 自定义一个命名空间,就类似于android:id="";中的android 不过此处我们定义的是andjoyo 像运行其他系统控件一样运用自定义控件就可以了
2.为MyView写一个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" > <TextView android:layout_width="fill_parent" android:layout_height="0.6dp" android:background="#0f00f0" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/iv_myview_icon" android:layout_width="35dp" android:layout_height="35dp" android:contentDescription="@string/description" android:src="@drawable/ic_launcher" /> <CheckBox android:id="@+id/cb_myview_item" android:layout_width="35dp" android:layout_height="35dp" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:clickable="false" android:focusable="false" /> <TextView android:id="@+id/tv_myview_item_age" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/cb_myview_item" android:layout_alignParentLeft="true" android:layout_marginLeft="51dp" android:text="@string/age" /> <TextView android:id="@+id/tv_myview_item_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/tv_myview_item_age" android:layout_alignLeft="@+id/tv_myview_item_age" android:text="@string/name" /> </RelativeLayout> <TextView android:layout_width="fill_parent" android:layout_height="0.6dp" android:background="#0f00f0" /> </LinearLayout>
、、
package cn.cbd.myview; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; public class MyViewActivity extends Activity { private ListView lv_main; private List<Person> persons; private MyAdapter adapter; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lv_main = (ListView) this.findViewById(R.id.lv_main); persons = getData(); adapter = new MyAdapter(this, persons); lv_main.setAdapter(adapter); lv_main.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { boolean ischecked = persons.get(position).isIschecked(); if (ischecked) { persons.get(position).setIschecked(false); } else { persons.get(position).setIschecked(true); } adapter.notifyDataSetChanged(); } }); } /** * 获取数据 * @return List<Person>对象 */ public List<Person> getData() { //往集合中添加数据,然后显示在listView上 List<Person> persons = new ArrayList<Person>(); for (int i = 0; i < 20; i++) { Person person = new Person("小王" + i, String.valueOf(15 + i)); person.setDrawable(this.getResources().getDrawable( R.drawable.ic_launcher)); persons.add(person); } return persons; } /** * 自定义Adapter 目的:为ListView设置适配器时使用 * @author Administrator * */ public class MyAdapter extends BaseAdapter { private Context context; private List<Person> persons; public MyAdapter(Context context, List<Person> persons) { this.context = context; this.persons = persons; } public int getCount() { return persons.size(); } public Object getItem(int position) { return persons.get(position); } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { Handler handler = null; if (convertView == null) { handler = new Handler(); //找到自定义控件上的各个控件 convertView = View.inflate(context, R.layout.myview, null); handler.tv_myview_item_name = (TextView) convertView .findViewById(R.id.tv_myview_item_name); handler.tv_myview_item_age = (TextView) convertView .findViewById(R.id.tv_myview_item_age); handler.iv_myview_icon = (ImageView) convertView .findViewById(R.id.iv_myview_icon); handler.cb_myview_item = (CheckBox) convertView .findViewById(R.id.cb_myview_item); //把自定义控件上的各个控件对应的一个Handler对象保存到Tag中 convertView.setTag(handler); } else { //从Tag中取出Handler对象 handler = (Handler) convertView.getTag(); } //为自定义控件上的各个控件设置内容 handler.tv_myview_item_name .setText(persons.get(position).getName()); handler.tv_myview_item_age.setText(persons.get(position).getAge()); handler.iv_myview_icon.setImageDrawable(persons.get(position) .getDrawable()); //判断集合中的某一项是否额比点击过 if (persons.get(position).isIschecked()) { //如果点击过,把CheckBox打上对钩 handler.cb_myview_item.setChecked(true); } else { //取消CheckBox对钩 handler.cb_myview_item.setChecked(false); } return convertView; } private final class Handler { private TextView tv_myview_item_name; private TextView tv_myview_item_age; private ImageView iv_myview_icon; private CheckBox cb_myview_item; } } }
上面的1,2步是很重要的。
下面就是把自定义的View添加到ListView上就可以了
package cn.cbd.myview; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; public class MyViewActivity extends Activity { private ListView lv_main; private List<Person> persons; private MyAdapter adapter; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lv_main = (ListView) this.findViewById(R.id.lv_main); persons = getData(); adapter = new MyAdapter(this, persons); lv_main.setAdapter(adapter); lv_main.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { boolean ischecked = persons.get(position).isIschecked(); if (ischecked) { persons.get(position).setIschecked(false); } else { persons.get(position).setIschecked(true); } adapter.notifyDataSetChanged(); } }); } /** * 获取数据 * @return List<Person>对象 */ public List<Person> getData() { //往集合中添加数据,然后显示在listView上 List<Person> persons = new ArrayList<Person>(); for (int i = 0; i < 20; i++) { Person person = new Person("小王" + i, String.valueOf(15 + i)); person.setDrawable(this.getResources().getDrawable( R.drawable.ic_launcher)); persons.add(person); } return persons; } /** * 自定义Adapter 目的:为ListView设置适配器时使用 * @author Administrator * */ public class MyAdapter extends BaseAdapter { private Context context; private List<Person> persons; public MyAdapter(Context context, List<Person> persons) { this.context = context; this.persons = persons; } public int getCount() { return persons.size(); } public Object getItem(int position) { return persons.get(position); } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { Handler handler = null; if (convertView == null) { handler = new Handler(); //找到自定义控件上的各个控件 convertView = View.inflate(context, R.layout.myview, null); handler.tv_myview_item_name = (TextView) convertView .findViewById(R.id.tv_myview_item_name); handler.tv_myview_item_age = (TextView) convertView .findViewById(R.id.tv_myview_item_age); handler.iv_myview_icon = (ImageView) convertView .findViewById(R.id.iv_myview_icon); handler.cb_myview_item = (CheckBox) convertView .findViewById(R.id.cb_myview_item); //把自定义控件上的各个控件对应的一个Handler对象保存到Tag中 convertView.setTag(handler); } else { //从Tag中取出Handler对象 handler = (Handler) convertView.getTag(); } //为自定义控件上的各个控件设置内容 handler.tv_myview_item_name .setText(persons.get(position).getName()); handler.tv_myview_item_age.setText(persons.get(position).getAge()); handler.iv_myview_icon.setImageDrawable(persons.get(position) .getDrawable()); //判断集合中的某一项是否额比点击过 if (persons.get(position).isIschecked()) { //如果点击过,把CheckBox打上对钩 handler.cb_myview_item.setChecked(true); } else { //取消CheckBox对钩 handler.cb_myview_item.setChecked(false); } return convertView; } private final class Handler { private TextView tv_myview_item_name; private TextView tv_myview_item_age; private ImageView iv_myview_icon; private CheckBox cb_myview_item; } } }
到此,这个小项目已经完成,这个主要就是让我们练一练自定义View的一些基本步骤,这是我们应该注意的
下面附件里有这个小项目的源码,大家可以运行在模拟器上看看,理解一下其中的代码的步骤,自己在练习练习就可以很容易的掌握了。
希望这个能帮到你们哦!