Android自定义控件

热门标签,流式标签的实现

2018-07-13  本文已影响152人  木小伍
废话不多说,先直接上最终的效果图(完整代码链接在底部) flexboxLayout.png
选中的标签.png

注:“小米超神”是在代码中固定添加的,为的是模拟自己新建标签功能。

FlexBoxLayout实现思路

1.为了更方便的实现选中与未选中状态,我使用的是checkbox
2.让它实现自动换行采用的FlexboxLayoutManager实现
3.为了达到复用的效果,我采取的是recycleview来实现
4.将选中的标签保存以及展示之前选中的标签,并且回传到上个页面
5.长按事件和点击事件的实现

实现过程

步骤1:呃......略过(只是样式调整,外带2个选择器。底部有完整项目的链接)。只要注意文字颜色的选择器要放在res/color文件夹下就行了。
步骤2,3:这里主要是采用recycleview+FlexBoxLayoutManager 来实现的,前者是为了达到复用的效果,减少内存消耗,后者是为了达到自动换行的效果。

首先需要在g'radle文件中添加flexbox的依赖

    implementation 'com.google.android:flexbox:1.0.0'

然后再recycleview的setManager方法中加入FlexBoxLayoutManager。

        FlexboxLayoutManager manager = new FlexboxLayoutManager(this);
        adapter = new RecyAdapter(this, R.layout.item_recyle_layout, datas);
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(manager);
步骤4:通过使用集合存储的方式,将选中的标签放在集合中,并且转成json数据的形式回传过去
  String jsonStr = "";
        if (checkList.size() > 0) {
            //固定添加“小米超神”标签
            if (!checkList.contains("小米超神"))
                checkList.add("小米超神");
            jsonStr = JsonUtils.toJson(checkList);
        }
        Intent intent = new Intent();
        intent.putExtra("jsonStr", jsonStr);
        setResult(Activity.RESULT_OK, intent);
        finish();
同样,需要展示之前选中的标签的话,同样也需要将之前选中的json数据格式的字符串,带到这个页面(标签中有个isCheck属性,这个在adapter中用于显示展示的状态)
  //去重操作
        String jsonStr = getIntent().getStringExtra("jsonStr");
        if (!TextUtils.isEmpty(jsonStr)) {

            checkList.addAll(JsonUtils.<String>json2arr(jsonStr));
            for (String title : checkList) {

                for (int i = 0; i < datas.size(); i++) {
                    if (datas.get(i).getTitle().equalsIgnoreCase(title)) {//总的标签里面含有这个标签
                        datas.get(i).setCheck(true);
                        break;
                    } else {
                        if (i == datas.size() - 1)
                            datas.add(new TagInfo(title).setCheck(true));//不存在 ----这种情况是属于自己能够创建新标签,这个功能没做
                    }
                }
            }
        }
步骤5:该步骤主要是通过recycleView的适配器来实现item的点击事件与长按事件(实现可以直接使用basequickAdapter或者自己封装)
     adapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(ViewGroup parent, View view, Object o, int position) {
                Log.i("TAG", "这个是点击事件");
                String tag = datas.get(position).getTitle();

                if (checkList.contains(tag)) { //当前已选中标签集合里面有该元素就删除
                    checkList.remove(tag);
                } else {
                    checkList.add(tag);
                }
            }
            @Override
            public boolean onItemLongClick(ViewGroup parent, View view, Object o, int position) {
                Toast.makeText(mActivity, "这个是长按事件", Toast.LENGTH_SHORT).show();
                return true;
            }
        });

对于FlexBoxLayout想要了解更多的可以参考下面的博客
FlexboxLayout的开源地址
Google 开源的 Android 排版库:FlexboxLayout
Android可伸缩布局-FlexboxLayout(支持RecyclerView集成)

TagFlowLayout实现思路

这种方法实现的思路,就很简单了。直接采用鸿洋的开源库。具体使用方法网上一大堆,具体参考hongyangAndroid该方法使用简单粗暴,只要按照提示,集成并不困难。这里不作详细介绍。这里需要提一下的是:

该方案不支持长按事件,需要自己实现!
该方案不支持长按事件,需要自己实现!
该方案不支持长按事件,需要自己实现!

如果不需要长按需求的同学建议使用该方案,需要长按需求的也可以使用该方案。接下来就贴出该方案的长按实现方法,主要在TagAdapter中的getView()方法中实现:

   @Override
    public View getView(FlowLayout parent, final int position, final TagInfo info) {

        final CheckBox checkBox = (CheckBox) LayoutInflater.from(mContext)
                .inflate(R.layout.item_recyle_layout, mFlowLayout, false);
        checkBox.setText(info.getTitle());
        //通过获取父布局,来设置长点击事件
        checkBox.post(new Runnable() {
            @Override
            public void run() { //避免创建事件监听的时候,控件还未实例化而造成空指针异常

                //为了避免影响选中事件,需要对其父控件(TagView)添加长按事件
                ViewParent parent1 = checkBox.getParent();
                if (null == parent1) return;
                TagView tagView = (TagView) parent1;
                tagView.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        checkBox.setTag(R.id.id_view_tag, position);
                        if (null != onLongClick) {
                            onLongClick.diyOnLongClick(position, info);
                        }
                        return true; //返回未true,onclick事件与onlongclick事件不同时发生
                    }
                });
            }
        });
        return checkBox;
    }

通过自己定义的长按事件,在标签触发长按事件的时候,回调自己申明的长按事件。

    /**
     * 自定义的长按事件
     */
    public interface DiyLongOnClickListener {
        void diyOnLongClick(int position, TagInfo info);
    }

    private DiyLongOnClickListener onLongClick;

    public FlowTagAdapter setOnLongClick(DiyLongOnClickListener onLongClick) {
        this.onLongClick = onLongClick;
        return this;
    }

至此,通过上段代码,可以在该方案中实现长按事件。
最后附上完整的demo代码链接

上一篇下一篇

猜你喜欢

热点阅读