RecyclerView动态标题

2023-12-19

我一直在使用 RecyclerView 添加动态标头。我提供了一个示例图像,如下所示。

在上图中,孩子们是有限的,但我的情况并非如此。标题之后我的孩子们不确定。

基本上代替header0这将是月份名称MAR以及下面发生的事情MAR月将至。数据来自 API,即 Web 服务,其中日期也即将到来,但我正在努力为上面解释的内容创建逻辑。

我尝试过的如下所示。下面是我创建的一个示例项目,因为原始代码是保密的,并且它与原始代码具有类似的逻辑问题。

MainActivity.java

    public class MainActivity extends AppCompatActivity {

    private RecyclerView rv;
    private ArrayList<Bean> beanArrayList = new ArrayList<>();
    private ArrayList<Bean> beanArrayListToPopulate = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        addDataToBean();

        rv = findViewById(R.id.rv);
        rv.setLayoutManager(new LinearLayoutManager(this));

        String prevMonth = null;

        for (int i = 0; i < beanArrayList.size(); i++) {

            Bean bean = new Bean();
            bean.setFirstName(beanArrayList.get(i).getFirstName());

            String newMonth;
            String createdDate = beanArrayList.get(i).getCreatedDate();

            if (createdDate != null) {
                newMonth = createdDate.split(" ")[1].trim();
                if (!newMonth.equalsIgnoreCase(prevMonth)) {
                    bean.setViewType(Adapter.VIEW_TYPE_ITEM);
                } else if (newMonth.equalsIgnoreCase(prevMonth)) {
                    bean.setViewType(Adapter.VIEW_TYPE_HEADER);
                    bean.setHeaderString(newMonth);
                }
                prevMonth = newMonth;
            }
            beanArrayListToPopulate.add(bean);
        }
        rv.setAdapter(new Adapter(beanArrayListToPopulate));
    }

    private void addDataToBean() {

        SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy");

        Date currentDate = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);

        for (int i = 0; i < 50; i++) {
            Bean bean = new Bean();
            calendar.add(Calendar.DATE, 10);
            Date newDate = calendar.getTime();
            bean.setCreatedDate(sdf.format(newDate));
            bean.setFirstName("Maulik - " + i);
            beanArrayList.add(bean);
        }
    }
}

适配器.java

    public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public static final int VIEW_TYPE_ITEM = 0;
    public static final int VIEW_TYPE_HEADER = 1;

    private ArrayList<Bean> mBeanList;

    public Adapter(ArrayList<Bean> beanList) {
        this.mBeanList = beanList;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if (viewType == VIEW_TYPE_HEADER) {
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
            return new VHHeader(view);
        } else if (viewType == VIEW_TYPE_ITEM) {
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
            return new VHItem(view);
        }
        throw new RuntimeException("There is no type that matches the type " + viewType + ". Make sure you are using view types correctly!");
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if (holder instanceof VHHeader) {
            ((VHHeader) holder).tvHeader.setText(mBeanList.get(position).getHeaderString());
        } else if (holder instanceof VHItem) {
            ((VHItem) holder).tvItem.setText(mBeanList.get(position).getFirstName());
        }
    }

    @Override
    public int getItemCount() {
        return mBeanList.size();
    }

    @Override
    public int getItemViewType(int position) {
        return mBeanList.get(position).getViewType();
    }

    class VHItem extends RecyclerView.ViewHolder {
        private TextView tvItem;

        public VHItem(View itemView) {
            super(itemView);
            tvItem = itemView.findViewById(R.id.tv_item);
        }
    }

    class VHHeader extends RecyclerView.ViewHolder {
        private TextView tvHeader;

        public VHHeader(View itemView) {
            super(itemView);
            tvHeader = itemView.findViewById(R.id.tv_header);
        }
    }
}

Bean.java

    public class Bean {

    private String createdDate;
    private String firstName;
    private int viewType;
    private String headerString;

    public String getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(String createdDate) {
        this.createdDate = createdDate;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public int getViewType() {
        return viewType;
    }

    public void setViewType(int viewType) {
        this.viewType = viewType;
    }

    public String getHeaderString() {
        return headerString;
    }

    public void setHeaderString(String headerString) {
        this.headerString = headerString;
    }
}

获取输出如下:

提前致谢。!


问题是你有一个列表Bean并且您想在新的月份时添加标题。因此,当月份发生变化时,beanArrayListToPopulate你需要添加Bean and标题。所以你需要创建一个额外的Bean添加标题。

所以 for 循环应该是这样的(在MainActivity)

String prevMonth = null;
String newMonth;
String createdDate;
for (Bean bean : beanArrayList) {
    createdDate = bean.getCreatedDate();
    // Create header Bean if necessary
    if (createdDate != null) {
        newMonth = createdDate.split(" ")[1].trim();
        if (!newMonth.equalsIgnoreCase(prevMonth)) {
            Bean headerBean = new Bean();
            headerBean.setViewType(Adapter.VIEW_TYPE_HEADER);
            headerBean.setHeaderString(newMonth);
            beanArrayListToPopulate.add(headerBean);
            prevMonth = newMonth;
        }
    }
    // Update data Bean
    bean.setViewType(Adapter.VIEW_TYPE_ITEM);
    beanArrayListToPopulate.add(bean);
}

编辑:你也可以尝试这种方法

但我认为我最好使用专用对象来不污染您检索的数据(Bean),信息仅用于显示它们。

所以你能做的就是创建一个ListItem对象并在您的适配器中使用它而不是Bean itself.

活动中

private ArrayList<Bean> beanArrayList = new ArrayList<>();
private ArrayList<ListItem> mListItems = new ArrayList<>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    addDataToBean();

    rv = findViewById(R.id.rv);
    rv.setLayoutManager(new LinearLayoutManager(this));

    String prevMonth = null;
    String newMonth;
    String createdDate;
    for (Bean bean : beanArrayList) {
        createdDate = bean.getCreatedDate();
        // Create a header if necessary
        if (createdDate != null) {
            newMonth = createdDate.split(" ")[1].trim();
            if (!newMonth.equalsIgnoreCase(prevMonth)) {
                ListItem headerItem = new ListItem(newMonth, Adapter.VIEW_TYPE_HEADER);
                mListItems.add(headerItem);
                prevMonth = newMonth;
            }
        }
        // Create a new item with the Bean data
        ListItem item = new ListItem(bean.getFirstName(), Adapter.VIEW_TYPE_ITEM);
        mListItems.add(item);
    }

    rv.setAdapter(new Adapter(mListItems));
}

在适配器中(我只放置了我更改过的内容)

private final ArrayList<ListItem> mItems;

public Adapter(ArrayList<ListItem> items) {
    this.mItems = items;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view;
    final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    if (viewType == VIEW_TYPE_HEADER) {
        view = inflater.inflate(R.layout.header, parent, false);
        return new VHHeader(view);
    } else if (viewType == VIEW_TYPE_ITEM) {
        view = inflater.inflate(R.layout.item, parent, false);
        return new VHItem(view);
    }
    throw new RuntimeException("There is no type that matches the type " + viewType + ". Make sure you are using view types correctly!");
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    ListItem item = mItems.get(position);
    // Note: You have the type information directly inside the ViewHolder so you don't need
    // to check the ViewHolder's instance type
    switch (holder.getItemViewType()) {
        case VIEW_TYPE_HEADER:
            ((VHHeader) holder).tvHeader.setText(item.getData());
            break;
        case VIEW_TYPE_ITEM:
            ((VHItem) holder).tvItem.setText(item.getData());
            break;
    }
}

列表项

public class ListItem {
    private String mData;
    private int mType;

    public ListItem(String data, int type) {
        mData = data;
        mType = type;
    }

    public String getData() {
        return mData;
    }

    public void setData(String data) {
        mData = data;
    }

    public int getType() {
        return mType;
    }
}

Note:也许代码需要一些调整,因为我还没有测试过。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RecyclerView动态标题 的相关文章

随机推荐

  • 在 JSONObject 中填充引号

    我正在构建一个 JSON 字符串以发送到我的 Web 服务 由于其中之一是用户输入的 因此可能存在双引号 我试图通过逃避来解决这个问题 String strValue height of 6 JSONObject json new JSON
  • 如何让 div 包围浮动的孩子?

    考虑以下代码 其中span元素漂浮在内部div 我怎样才能使div环绕浮动子元素 以便 1px 边框环绕子元素 div style border 1px solid 000 span Content span span Content sp
  • 如何列出我的应用程序支持的语言

    该应用程序有许多本地化文件夹 values cs values da values de values es 如何在运行时枚举所有支持的语言 当然 我可以定义一些常量来列出所有值 cs da de 但希望避免这样做 我认为这可行 enum
  • 升级到 AngularFire 5.0

    我正在使用 ionic 3 和 firebase 到目前为止 我使用 angularfire 4 0 以下代码为我提供了来自 firebase 的数据的可观察值 obsToData FirebaseObjectObservable
  • 扇形陷阱和裂缝陷阱 - 数据库

    谁能告诉我什么是裂缝陷阱 也许也是粉丝陷阱 因为我不太清楚 另外 请提供易于理解的示例 通过 Chen 符号 到目前为止我的理解 我理解 Fan trap 是 M 1 1 M 这表明实体之间的路径是不明确的 我明白那个 例如 如果 M 代表
  • 尽管连接字符串超时 3 秒,Sql 连接仍等待 15 秒

    我有一个通过本地网络使用 Microsoft SQL 2008 服务器的网站 有时 SQL Server 机器会重新启动 因此网站无法连接到数据库 如果机器已启动并运行 则will反应快 如果已关闭 则无需等待 15 秒 3秒就可以了 我想
  • 异常助手中缺少“查看详细信息”

    最近 在 Visual Studio 2015 update 3 中 异常助手的行为发生了变化 我不再看到 查看详细信息 选项 并且堆栈跟踪也不会展开 如果我选择 使用托管兼容模式 它就会起作用 所有 C 项目都会发生这种情况 另一件事是
  • 通过 Applescript 发送电子邮件时发件人不正确

    下面的 Applescript 是我多年来使用的形式 基本上是一种众所周知的使用 Applescript 发送电子邮件的方法 tell application Mail set newMessage to make new outgoing
  • cakephp 2 css、javascript 和链接在本地计算机/localhost 上不起作用

    我应该在 webroot 文件夹上使用什么 htaccess 设置 似乎这是布局中所有链接不起作用的罪魁祸首 这是 webroot 文件夹内的 htaccess 代码
  • 使用 Powershell 替换列值

    我正在尝试循环遍历 csv 并替换名为的列中的任何值Enabled from True to A Import Csv test csv Where Object Enabled eq True gt what goes here to r
  • Haskell 函数 (a -> [b]) -> [a -> b]

    我有一个函数seperateFuncs这样 seperateFuncs a gt b gt a gt b seperateFuncs xs x gt map x xs 我想知道相反的情况是否存在 即是否有一个函数 joinFuncs a g
  • SWIG:以 OO 方式包装 C API

    我有一个 C 不是 C 库 它始终使用函数的第一个参数作为上下文对象 让我们调用类型t context 我想使用 SWIG 生成 C 包装器 保持这种调用风格 即 不是将函数或多或少地隔离 而是将它们包装为某个类中的方法并访问t conte
  • Xcode 10 上的模拟器变得非常慢

    在 Xcode 9 上一切都很完美 但是更新到 Xcode 10 后 模拟器开始出现巨大的滞后 超级简单的动画以 2 fps 的速度运行 而当模拟器上的动画运行时 整个 Mac OS 的运行速度非常慢 有人知道发生了什么以及如何解决这个问题
  • 为什么会出现这个未处理的 org.apache.tiles.impl.CannotRenderException?

    实际上 我正在致力于在在线考试项目上实现 Struts Spring 和 Hibernate 集成 但是当我在 JSP 页面中提交值时 它会抛出以下错误 Struts 问题报告 Struts has detected an unhandle
  • Django 应用程序中的访问控制允许来源

    我正在为基于 Django 的应用程序开发 Phonegap 应用程序 但是当尝试进行 Ajax 调用时 我收到此错误 XMLHttpRequest cannot load http domain herokuapp com getcsrf
  • UIWebView:页面什么时候真正完成加载?

    我需要知道 当 UIWebView 完全加载网页时 我的意思是 当所有重定向完成并且动态加载的内容准备就绪时 真的完全完成了 我尝试注入 javascript 查询document readyState complete 但这似乎不太可靠
  • 使用 IoC、依赖注入、工作单元的 Linq to SQL 的存储库模式

    似乎有很多关于为 Linq to SQL 实现存储库模式的示例 其中大多数以 IRepository 和 DI 为特色 有些已经实现了工作单元 有些则没有 我尝试阅读 SO 和 Google 对 Linq to SQL 存储库模式的搜索返回
  • 将枚举转换为值数组(将所有 JSON 值放入数组中)

    我用这个方法JavaScript 中的枚举 https stackoverflow com questions 287903 enums in javascript在我们的代码中创建枚举 So var types WHITE 0 BLACK
  • 无法识别获取内容命令

    我们有通常在 UNIX 环境中执行的脚本 以下是脚本中的一行 command gt use bin tail n 1 path grep silent F message rm f path 当在 PowerShell 中运行时 use b
  • RecyclerView动态标题

    我一直在使用 RecyclerView 添加动态标头 我提供了一个示例图像 如下所示 在上图中 孩子们是有限的 但我的情况并非如此 标题之后我的孩子们不确定 基本上代替header0这将是月份名称MAR以及下面发生的事情MAR月将至 数据来