最近项目需要做个热门搜索标签功能。
想法主要有2个,一是做个listview或者gridview,但是有个很明显的缺陷就是需要这些关键字长度相似,不然就会出现布局问题,很难看且很死板。二是自定义一种listview,子item自适应父类的大小排列。就像在应用汇里的应用标签那样。幸运的是在github找到了这个相关开源控件flowlayout。
https://github.com/ApmeM/android-flowlayout
flowlayout的作用是智能测量子view的大小进行线性布局,在线性布局的基础上,如果要添加的子view要超过了父类尺寸,则智能换行。
应用汇截图如左侧效果,随便写了个demo,效果图如右侧(只是一个Demo,用到项目中只需要优化一下就能做出应用汇的效果)
看看怎么做吧。flowlayout是一个布局,只要添加view进去,就会自动智能线性排列,并且有很多排列方式,具体设置请看github上项目介绍,今天只讲默认的布局方式,如何做出仿应用汇这种标签效果。
首先标签应该是个类,有自己的属性,这样用户点击了标签才能进行下一步的操作,也就是对数据建模。
public class FlowTag {
private int id;//id
private String title;//标签上的文字
public FlowTag(int _id,String _title){
this.setId(_id);
this.setTitle(_title);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
简单建模,Tag类,每个tag都有自己的id和自己的title。
数据好了,第二步是继承flowlayout自定义TagListView。它是一个容器,只要把数据塞进容器就好了。
public class FlowTagList extends FlowLayout {
public FlowTagList(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public FlowTagList(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
// TODO Auto-generated constructor stub
}
public FlowTagList(Context context, AttributeSet attributeSet, int defStyle) {
super(context, attributeSet, defStyle);
// TODO Auto-generated constructor stub
}
private List<FlowTag> mDataList = new ArrayList<FlowTag>();
private onItemClickListener mListenr;
//添加一个子view到listview中,并使其和tag类数据绑定
private void inflateTag(final FlowTag tag) {
if (tag == null)
return;
//这里选择插入一个textview。也可以自定义layout的view通过LayoutInflater引入布局,总之添加进来一个子view就ok。
TextView tv = new TextView(getContext());
tv.setText(tag.getTitle());
addView(tv);
tv.setFocusable(true);
tv.setClickable(true);
tv.setTextColor(Color.WHITE);
tv.setBackgroundResource(R.drawable.common_item_bg_normal);
tv.setPadding(10, 10, 10, 10);
//设置点击事件,并传递给接口。当然不只是能设置点击事件,任何事件都可以设置,如果需要只要稍微修改一下接口或者添加新的接口就OK
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (mListenr != null) {
mListenr.onClick(v, tag);
}
}
});
}
//添加数据
public void setData(List<FlowTag> list) {
if (list == null || list.isEmpty())
return;
this.mDataList = list;
for (FlowTag tag : mDataList)
inflateTag(tag);
}
//设置子item点击事件
public void setOnItemClickListener(onItemClickListener listener) {
this.mListenr = listener;
}
}
//自定义一个接口,用来传递点击事件
interface onItemClickListener {
public void onClick(View v, FlowTag tag);
}
这个类自定义了listview。内部实现添加子view并绑定tag数据,为所有子view设置接口监听点击事件。
子view可以是自己定义任何控件(这里图省事用了textview),十分灵活,与我们的tag数据绑定起来。
接口完全可以自定义,在添加子view的时候为它们添加监听接口,并传递出来给我们自己定义的接口。
好了,activity中调用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FlowTagList tagList=(FlowTagList) findViewById(R.id.taglist);
List<FlowTag>list=new ArrayList<FlowTag>();
list.add(new FlowTag(0, "安全必备"));
list.add(new FlowTag(0, "音乐"));
list.add(new FlowTag(0, "父母学"));
list.add(new FlowTag(0, "上班族必备"));
list.add(new FlowTag(0, "杰兔加速"));
list.add(new FlowTag(0, "杰兔今日联播"));
list.add(new FlowTag(0, "杰兔看世界"));
list.add(new FlowTag(0, "智能吧"));
list.add(new FlowTag(0, "智能吧电视论坛"));
list.add(new FlowTag(0, "小公举"));
list.add(new FlowTag(0, "sante"));
list.add(new FlowTag(0, "唐僧肉"));
tagList.setData(list);
tagList.setOnItemClickListener(new onItemClickListener() {
@Override
public void onClick(View v, FlowTag tag) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "点击标签"+tag.getTitle(), Toast.LENGTH_SHORT).show();
}
});
}
最后注意,xml布局中,layout_height=wrap_content。因为我们的需求是横向填满的,垂直上是自适应的。当然也可以根据自己的项目进行微调。
所有定义和数据绑定都很灵活,主要是介绍flowlayout这个开源控件,效果很棒!使用很灵活。