我们平常使用ListView多半都是用来展示数据的,且每个item的模式都是一样的。但是还有更多的时候会出现不一样的布局,比如你手机联系人的方式。好了不多说,看效果图吧!
为什么我会想到写这篇文章,事情的起因是我在项目中遇到一个需求。需要实现一个WiFi列表界面,熟悉手机的盆友应该知道WiFi列表不是我们随便写一个ListVIew就能实现的了。开始我的想法是用线性布局,中间夹杂需要的标题栏布局等,可是我操作了大半天,发现一个很致命的问题,已经连接过的WiFi是不会出现在周围热点的列表里面的。(因为项目的WiFi列表实现了自动刷新)如果按照这种思路走下去,在每次刷新之后都要一个一个对照,然后将已经连接的从列表里面移除。很显然这个效率太低了,于是就问同事,同事就告诉我说用一个列表啊。嗯!确实很感谢他。
后来我又开始了不断寻找的道路。在找了很多资料以后终于找到了答案(可能是我自身能力不足,有的东西真的看不明白吧)。关键在于Adapter里面的两个方法。
@Override
public int getViewTypeCount() {
return 2;
}
这个方法就是返回你需要展示不同的类型数量,我的项目就两个,所以返回2.
@Override
public int getItemViewType(int position) {
if (types == 0){
if (position == 3){
return 0;
}else {
return 1;
}
}else {
return position % 2;
}
}
这个是根据位置返回你需要展示的类型,待会我们就会用到。比如说返回0说明我想用1号布局,
返回1说明我想用2号布局。特别注意一点的这里返回的值必须从0开始,
且不能大于你返回的类型总数(就是上一个方法返回的数值,原理是看到大神这么说的<(* ̄▽ ̄*)/)
当然你可以在这里加上自己的逻辑判断哪个位置返回什么,我这里只是简单的显示2个布局。
好来看适配器代码
public class ListAdapter extends BaseAdapter {
private List<String> contents;
private LayoutInflater inflater;
//模拟判断效果,你可以改成其他的值,当然在getItemViewType里面的值也要变一下
private int types = 1;
public ListAdapter(List<String> contents, Context context) {
this.contents = contents;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return contents == null ? 0 :contents.size();
}
@Override
public Object getItem(int position) {
return contents.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
int type = getItemViewType(position);
if (view == null) {
switch (type) {
case 0:
view = inflater.inflate(R.layout.item_right, parent, false);
break;
case 1:
view = inflater.inflate(R.layout.item_left, parent, false);
break;
}
}
ViewHolder holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder();
holder.imageView = (ImageView) view.findViewById(R.id.image);
holder.textView = (TextView) view.findViewById(R.id.text_content);
}
holder.textView.setText(contents.get(position));
return view;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
if (types == 0){
if (position == 3){
return 0;
}else {
return 1;
}
}else {
return position % 2;
}
}
static class ViewHolder {
TextView textView;
ImageView imageView;
}
}
注意这个方法
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
int type = getItemViewType(position);
if (view == null) {
switch (type) {
case 0:
view = inflater.inflate(R.layout.item_right, parent, false);
break;
case 1:
view = inflater.inflate(R.layout.item_left, parent, false);
break;
}
}
ViewHolder holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder();
holder.imageView = (ImageView) view.findViewById(R.id.image);
holder.textView = (TextView) view.findViewById(R.id.text_content);
}
holder.textView.setText(contents.get(position));
return view;
}
这里我们根据在getItemViewType里面返回的值进行判断选择不同的布局展示。
布局代码(如果你实现不了这种布局的话我也没办法帮你了骚年)我就不贴了。最后贴上MainActivity代码
public class MainActivity extends AppCompatActivity {
private ListView listView;
private List<String> contents;
private ListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.list_content);
contents = new ArrayList<>();
for (int i = 1;i < 50;i++){
contents.add("这是第 " + i + "条item");
}
adapter = new ListAdapter(contents,this);
listView.setAdapter(adapter);
}
}
怎么样,还是比较简单的吧,问题还没有结束哦。如果你设置了点击监听事件你会发现每个item都是会响应点击事件的。如果我想让第四个不能响应点击事件怎么办?这个你可以再Adapter里面重写这个方法
@Override
public boolean isEnabled(int position) {
return super.isEnabled(position);
}
这个你同样根据位置来判断就好比如说我想让第四个不能点击那就可以写成这样
public boolean isEnabled(int position) {
if (position == 4){
//返回false表示不可以点击
return false;
}else {
//返回true表示可以点击
return true;
}
}
好了,到此,已经实现了不同布局的加载以及某个item不可点击。正所谓好事多磨,仅仅靠这个是不可能做出很好的内容的,加油吧各位!自己也要加油!