用 adapter 的形式封装一下 LinearLayout 的 addView

项目中经常会有一些重复率高,相似度高的UI布局,比如下面的:

image.png

image.png

image.png

这些UI可能嵌在列表里,可能在一些页面中,他们的特点是有好多相识的 item,但又不会很多。实现也有很多种,比如用 RecycleView,在布局中一个个的写,又或者搞一个 layout,动态 add 进去。

那么这里当然是用动态 add 进一个 layout 省事了,那么就需要封装。这里layout用LinearLayout,因为他是线性的,可横可竖,比较耐操。

怎么封装,这里是使用 adapter 的形式,好处是这样可以用数据的方式控制布局,而且可以通用。整体代码技术含量不高,意思是很简单。。下面贴上完整代码,感觉有用的可以拿走改成功能更多的东西。。

不过有一个问题我不太懂,望大佬们指点一下,就是将下面 Layout 的代码转成 Kotlin ,泛型要怎么搞。不太懂,这里暂时先用 java 写了。

public class LinearTagLayout extends LinearLayout
        implements LinearTagAdapter.OnDataChangedListener {

    private final float leftMargin;
    private final float topMargin;
    private final float rightMargin;
    private final float bottomMargin;
    private final float itemWeight;
    private final LayoutParams defItemParams;

    public LinearTagLayout(Context context) {
        this(context, null);
    }

    public LinearTagLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LinearTagLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LinearTagLayout);
        leftMargin = ta.getDimension(R.styleable.LinearTagLayout_item_left_margin, 0);
        topMargin = ta.getDimension(R.styleable.LinearTagLayout_item_top_margin, 0);
        rightMargin = ta.getDimension(R.styleable.LinearTagLayout_item_right_margin, 0);
        bottomMargin = ta.getDimension(R.styleable.LinearTagLayout_item_bottom_margin, 0);
        itemWeight = ta.getFloat(R.styleable.LinearTagLayout_item_weight, 0);

        float itemWidth = ta.getDimension(R.styleable.LinearTagLayout_item_view_width, LayoutParams.WRAP_CONTENT);
        float itemHeight = ta.getDimension(R.styleable.LinearTagLayout_item_view_height, LayoutParams.WRAP_CONTENT);
        int itemGravity = ta.getInt(R.styleable.LinearTagLayout_item_view_gravity, -1);

        defItemParams = new LayoutParams((int) itemWidth, (int) itemHeight);
        defItemParams.topMargin = (int) topMargin;
        defItemParams.leftMargin = (int) leftMargin;
        defItemParams.rightMargin = (int) rightMargin;
        defItemParams.bottomMargin = (int) bottomMargin;
        if (itemGravity != -1) {
            if (itemGravity == 0) {
                defItemParams.gravity = Gravity.CENTER_VERTICAL;
            } else if (itemGravity == 1) {
                defItemParams.gravity = Gravity.CENTER_HORIZONTAL;
            } else if (itemGravity == 2) {
                defItemParams.gravity = Gravity.LEFT;
            } else if (itemGravity == 3) {
                defItemParams.gravity = Gravity.TOP;
            } else if (itemGravity == 4) {
                defItemParams.gravity = Gravity.RIGHT;
            } else if (itemGravity == 5) {
                defItemParams.gravity = Gravity.BOTTOM;
            }
        }
        ta.recycle();
    }

    private LinearTagAdapter adapter;
    private OnTagClickListener itemClickListener;

    public void setAdapter(LinearTagAdapter adapter) {
        this.adapter = adapter;
        this.adapter.setOnDataChangedListener(this);
        changeAdapter();
    }

    public LinearTagAdapter getAdapter() {
        return adapter;
    }

    public void setOnItemClickListener(OnTagClickListener listener) {
        itemClickListener = listener;
    }

    private void changeAdapter() {
        if (adapter == null) return;
        removeAllViews();
        for (int i = 0; i < adapter.getCount(); i++) {
            View tagView = adapter.getView(i, adapter.getItem(i));
            tagView.setLayoutParams(defItemParams);
            int finalI = i;
            tagView.setOnClickListener(view -> {
                if (itemClickListener != null) {
                    itemClickListener.onTagClick(view, finalI);
                }
            });
            if (itemWeight != 0) {
                addView(tagView, new LayoutParams(0, LayoutParams.WRAP_CONTENT, itemWeight));
            } else {
                addView(tagView);
            }
        }
    }
    
    @Override
    public void onChanged() {
        changeAdapter();
    }

    interface OnTagClickListener {
        void onTagClick(View view, int position);
    }
}
复制代码
abstract class LinearTagAdapter<T>(private val list: MutableList<T> = mutableListOf()) {

    private var listener: OnDataChangedListener? = null

    fun submitList(list: MutableList<T>) {
        this.list.clear()
        this.list.addAll(list)
        notifyDataChanged()
    }

    fun getCount(): Int = list.size

    fun getItem(position: Int): T? = list.getOrNull(position)

    fun notifyDataChanged() {
        listener?.onChanged()
    }

    abstract fun getView(position: Int, data: T?): View

    fun setOnDataChangedListener(listener: OnDataChangedListener?) {
        this.listener = listener
    }

    interface OnDataChangedListener {
        fun onChanged()
    }
}
复制代码
<declare-styleable name="LinearTagLayout">
    <attr name="item_left_margin" format="dimension" />
    <attr name="item_top_margin" format="dimension" />
    <attr name="item_right_margin" format="dimension" />
    <attr name="item_bottom_margin" format="dimension" />
    <attr name="item_view_width" format="dimension" />
    <attr name="item_view_height" format="dimension" />
    <attr name="item_view_gravity" format="enum">
        <enum name="CENTER_VERTICAL" value="0" />
        <enum name="CENTER_HORIZONTAL" value="1" />
        <enum name="LEFT" value="2" />
        <enum name="TOP" value="3" />
        <enum name="RIGHT" value="4" />
        <enum name="BOTTOM" value="5" />
    </attr>
    <attr name="item_weight" format="float" />
</declare-styleable>
复制代码

用法:

layout?.adapter = object : LinearTagAdapter<String>(dataList) {
    override fun getView(position: Int, data: String?): View {
        val view = ImageView(context)
        view.adjustViewBounds = true
        view.loadImage(data)
        return view
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享