在开发项目工程中,有时候系统的一下控件即View无法满足我们的需求,此时就需要自定义View

在这里,我们举一个简单的自定义View的小例子

需求:如下图,自定义一个View 并显示在ListView上自定义View控件实例_自定义Veiw

其中ListView每个字条目都是自定义的一个View(包括一个ImageView 两个TextView 和一个CheckBox)

自定义View控件实例_自定义Veiw_02

 

以往我们用的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的一些基本步骤,这是我们应该注意的

 

下面附件里有这个小项目的源码,大家可以运行在模拟器上看看,理解一下其中的代码的步骤,自己在练习练习就可以很容易的掌握了。

希望这个能帮到你们哦!