安卓开发手机移动程序开发

QMUIStickySectionLayout使用方法

2020-09-18  本文已影响0人  九狼JIULANG

这里介绍的是Sticky Section for List

QMUIStickySectionLayout 用于解决两个需求场景:

1.可折叠展开的 section 列表(list/grid)

2.类似 iOS 一样可以在列表(list/grid)滚动过程中悬浮(sticky)当前的 section header

截图

二级条目

QMUIStickySectionLayout 的Wiki很简略难以看懂

开始

导入库我们就不说了直接上重点


1.通过XML代码构造QMUIStickySectionLayout实例:

<com.qmuiteam.qmui.widget.section.QMUIStickySectionLayout
  android:id="@+id/section_layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent"/>

2. 准备好两个数据模型,头部和脚部

Header

import cn.jiulang.efficiency.UIcomponent.UINote.AccountBook.Tree.ItemBase.SectionHeader;
import com.qmuiteam.qmui.widget.section.QMUISection;
public class SectionHeader implements QMUISection.Model<SectionHeader> {
    private String tvWeek;
    private String tvDate;
    private String tvTotalAmount;
    public SectionHeader(String name1, String name2, String name3) {
        this.tvWeek = name1;
        this.tvDate = name2;
        this.tvTotalAmount = name3;
    }
    public String getWeek() {
        return tvWeek;
    }
    public String getDate() {
        return tvDate;
    }
    public String getTotalAmount() {
        return tvTotalAmount;
    }
    @Override
    public SectionHeader cloneForDiff() {
        return new SectionHeader(getWeek(), getDate(), getTotalAmount());
    }
    @Override
    public boolean isSameItem(SectionHeader other) {
      return tvWeek == other.tvWeek || (tvWeek != null && tvWeek.equals(other.tvWeek))
            && tvDate == other.tvDate || (tvDate != null && tvDate.equals(other.tvDate))
            && tvTotalAmount == other.tvTotalAmount || (tvTotalAmount != null && tvTotalAmount.equals(other.tvTotalAmount));           
    }
    @Override
    public boolean isSameContent(SectionHeader other) {
        return true;
    }
}

Item

public class SectionItem implements QMUISection.Model<SectionItem> {
    private String tvTag;
    private String tvNote;
    private String tvAccount;

    public SectionItem(String name1, String name2, String name3) {
        this.tvTag = name1;
        this.tvNote = name2;
        this.tvAccount = name3;
    }
    public String getTag() {
        return tvTag;
    }
    public String getNote() {
        return tvNote;
    }
    public String getAccount() {
        return tvAccount;
    }
    @Override
    public SectionItem cloneForDiff() {
        return new SectionItem(getTag(), getNote(), getAccount());
    }
    @Override
    public boolean isSameItem(SectionItem other) {
        return //tvTag == other.tvTag || (tvTag != null && tvTag.equals(other.tvTag))
          //  && tvNote == other.tvNote || (tvNote != null && tvNote.equals(other.tvNote))
            tvAccount == other.tvAccount || (tvAccount != null && tvAccount.equals(other.tvAccount));         
    }
    @Override
    public boolean isSameContent(SectionItem other) {
        return true;
    }
}

QMUISection.Model 的接口 isSameItem 与 isSameContent 的概念都来源于 DiffUtil, 如果对 DiffUtil还不了解的话, 可以去官网查看与学习。

在 QMUIDemo 中,提供了 SectionHeader 和 SectionItem 的示例,可点击查看。

在准备好这两个 model 后,我们就可以构建 adapter 需要用到的 QMUISection<H, T> 了, 其中 H、T 就是之前准备的 SectionHeader 和 SectionItem。

3.构建Adapter

public class QDListSectionAdapter extends QMUIDefaultStickySectionAdapter<SectionHeader, SectionItem> {
    private TextView tvTag ,tvNote,tvAccount;
    @NonNull
    @Override
    protected ViewHolder onCreateSectionHeaderViewHolder(@NonNull ViewGroup viewGroup) {
        return new ViewHolder(new QDSectionHeaderView(viewGroup.getContext()));
    }
    public QDListSectionAdapter() {
    }
    public QDListSectionAdapter(boolean removeSectionTitleIfOnlyOneSection) {
        super(removeSectionTitleIfOnlyOneSection);
    }
    @NonNull
    @Override
    protected ViewHolder onCreateSectionItemViewHolder(@NonNull ViewGroup viewGroup) {
        Context context = viewGroup.getContext();
        //这里是通过xml绑定布局,当然你也可以用代码new出来,方法请看头部视图
        View itemView = LayoutInflater.from(context).inflate(R.layout.note_rv_tree_second, viewGroup, false);
       
        return new ViewHolder(itemView);
    }
    @Override
    protected void onBindSectionHeader(final ViewHolder holder, final int position, QMUISection<SectionHeader, SectionItem> section) {
        QDSectionHeaderView itemView = (QDSectionHeaderView) holder.itemView;
        itemView.render(section.getHeader(), section.isFold());
        //点击事件
        itemView.getArrowView().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {                 
                    int pos = holder.isForStickyHeader ? position : holder.getAdapterPosition();
                    toggleFold(pos, false);
                }
            });
    }
    @Override
    protected void onBindSectionItem(ViewHolder holder, int position, QMUISection<SectionHeader, SectionItem> section, int itemIndex) {
        //获取id
        tvTag = holder.itemView.findViewById(R.id.Tag_text);
        //设置文本
        tvTag.setText(section.getItemAt(itemIndex).getTag());
        tvNote = holder.itemView.findViewById(R.id.Note_text);
        tvNote.setText(section.getItemAt(itemIndex).getNote());
        tvAccount = holder.itemView.findViewById(R.id.Account_text);
        tvAccount.setText(section.getItemAt(itemIndex).getAccount());
       
    }
}

创建头部视图(不然会报空指针)

public class QDSectionHeaderView extends RelativeLayout {

    private TextView tvWeek,tvDate,tvTotalAmount; 
private ImageView mArrowView;  private int headerHeight = QMUIDisplayHelper.dp2px(getContext(), 56);
    public QDSectionHeaderView(Context context) {
        this(context, null);
    }
    public QDSectionHeaderView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        setOrientation(LinearLayout.HORIZONTAL);
        setGravity(Gravity.CENTER_VERTICAL);
        setBackgroundColor(Color.WHITE);
        int paddingHor = QMUIDisplayHelper.dp2px(context, 24);
        mTitleTv = new TextView(getContext());
        mTitleTv.setTextSize(20);
        mTitleTv.setTextColor(Color.BLACK);
        mTitleTv.setPadding(paddingHor, 0, paddingHor, 0);
        addView(mTitleTv, new LinearLayout.LayoutParams(
                0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f));
        mArrowView = new AppCompatImageView(context);
        mArrowView.setImageDrawable(QMUIResHelper.getAttrDrawable(getContext(),
                R.attr.qmui_common_list_item_chevron));
        mArrowView.setScaleType(ImageView.ScaleType.CENTER);
        addView(mArrowView, new LinearLayout.LayoutParams(headerHeight, headerHeight));tvWeek = new TextView(getContext());

        tvWeek.setTextSize(21);

        tvWeek.setTextColor(Color.BLACK);

        RelativeLayout.LayoutParams rlWeek = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        rlWeek.addRule(RelativeLayout.ALIGN_PARENT_LEFT);

        rlWeek.addRule(RelativeLayout.CENTER_VERTICAL);

        layout.addView(tvWeek, rlWeek);

        tvDate = new TextView(getContext());

        tvDate.setTextSize(16);

        tvDate.setTextColor(Color.BLACK);     

        RelativeLayout.LayoutParams rlDate = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        //与父组件顶部对齐

        rlDate.addRule(RelativeLayout.ALIGN_PARENT_TOP);

        //横向居中

        rlDate.addRule(RelativeLayout.CENTER_HORIZONTAL); 

        layout.addView(tvDate, rlDate);

        tvTotalAmount = new TextView(getContext());

        tvTotalAmount.setTextSize(19);

        tvTotalAmount.setTextColor(Color.BLACK);

        RelativeLayout.LayoutParams rlTotalAmount = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        rlTotalAmount.addRule(RelativeLayout.LEFT_OF, mArrowView.getId());

        rlTotalAmount.addRule(RelativeLayout.CENTER_VERTICAL);

        layout.addView(tvTotalAmount, rlTotalAmount);

    }
    public ImageView getArrowView() {
        return mArrowView;
    }
    public void render(SectionHeader header, boolean isFold) {
        mTitleTv.setText(header.getText());
        mArrowView.setRotation(isFold ? 0f : 90f);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec,
                MeasureSpec.makeMeasureSpec(headerHeight, MeasureSpec.EXACTLY));
    }

adaper就写好了

接下来就初始化就行了

private QMUIStickySectionLayout mSectionLayout;
    private RecyclerView.LayoutManager mLayoutManager;
    protected static QMUIStickySectionAdapter<SectionHeader, SectionItem, QMUIStickySectionAdapter.ViewHolder> mAdapter;
    private void initAdapter() {
        mLayoutManager = createLayoutManager();
        mSectionLayout.setLayoutManager(mLayoutManager);
        mAdapter = createAdapter();     
        mSectionLayout.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.aword_fade_enter));
    }
    private void initAdapterLogicalOperation() {
        mAdapter.setCallback(new QMUIStickySectionAdapter.Callback<SectionHeader, SectionItem>() {
                @Override
                public void loadMore(final QMUISection<SectionHeader, SectionItem> section, final boolean loadMoreBefore) {
                }
                //点击事件
                @Override
                public void onItemClick(QMUIStickySectionAdapter.ViewHolder holder, int position) {
                    if (holder.getItemViewType() != 1) {
                        int pos = holder.isForStickyHeader ? position : holder.getAdapterPosition();
                        mAdapter.toggleFold(pos, false);                 
                    }
                    //  Toast.makeText(getContext(), "click item " + mAdapter.getItemIndex(position), Toast.LENGTH_SHORT).show();
                }
                //长按事件
                @Override
                public boolean onItemLongClick(QMUIStickySectionAdapter.ViewHolder holder, int position) {
                    int FirstPos = mAdapter.getSectionIndex(position);
                    int SecondPos =mAdapter.getItemIndex(position);             
                  //  ItemPopupWindow.show(getContext(), holder.itemView, holder.getItemViewType(), FirstPos, SecondPos);
                    // Toast.makeText(getContext(), "一级条目" +FirstPos+ "二级"+ SecondPos, Toast.LENGTH_SHORT).show();
                    return true;
                }
            });
        mSectionLayout.setAdapter(mAdapter, true);
        mAdapter.setData(getList(0));
    }
protected QMUIStickySectionAdapter<SectionHeader, SectionItem, QMUIStickySectionAdapter.ViewHolder> createAdapter() {
        return new QDListSectionAdapter(true);
    }
    protected RecyclerView.LayoutManager createLayoutManager() {
        return new LinearLayoutManager(getContext()) {
            @Override
            public RecyclerView.LayoutParams generateDefaultLayoutParams() {
                return new RecyclerView.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            }
        };
    }

最后加载数据

模拟加载

  private static ArrayList<QMUISection<SectionHeader, SectionItem>> getList() {
        ArrayList<QMUISection<SectionHeader, SectionItem>> list = new ArrayList<>();
       
    int n = 0;
    for (int i=0;i < 5;i++) {
        SectionHeader header = new SectionHeader("周末"+i,"时间"+ i,"金额"+ i);             
        ArrayList<SectionItem> contents = new ArrayList<>();
        for (int j = 0; j <20/* 二级条目辅助数据*/; j++) {
            contents.add(new SectionItem("标签"+n, "备注"+n, "金额"+n));
            n++;
        }
        QMUISection<SectionHeader, SectionItem> section = new QMUISection<>(header, contents, i != unfold);         
        list.add(section);
    }
return list;
}
创作不易点个赞吧!
上一篇 下一篇

猜你喜欢

热点阅读