You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中如何实现支持View All交互的可滚动分组展开布局?

Hey there! Let's walk through how to build this expandable grouped list layout with global scrolling—here's a practical approach tailored to your needs:

1. First, Define Your Data Model

Start by structuring your data to match the requirements. Here's a TypeScript example (easily adaptable to other languages/frameworks):

// 子项的数据结构
interface ListItem {
  icon: string; // 可以是图标名称、SVG代码或者图片URL
  title: string;
  price: string;
  helpText: string;
}

// 分组的数据结构
interface Group {
  title: string;
  subtitle: string;
  items: ListItem[];
}

// 示例数据
const groupedData: Group[] = [
  {
    title: "Electronics",
    subtitle: "Top picks for your home",
    items: [
      { icon: "📱", title: "Smartphone", price: "$699", helpText: "2-year warranty" },
      { icon: "💻", title: "Laptop", price: "$1299", helpText: "1TB SSD storage" },
      { icon: "🎧", title: "Wireless Headphones", price: "$199", helpText: "30-hour battery life" }
    ]
  },
  {
    title: "Home Goods",
    subtitle: "Essentials for everyday living",
    items: [
      { icon: "🛋️", title: "Throw Pillow", price: "$29", helpText: "Machine washable" },
      { icon: "🍳", title: "Non-stick Pan", price: "$49", helpText: "Induction compatible" }
    ]
  }
];
2. Build the Expandable Group Component

Next, create a reusable component for each group that handles the expand/collapse logic. Using React as an example (but the logic translates to Vue, Angular, or vanilla JS too):

import { useState } from "react";

const GroupItem = ({ group }) => {
  // 跟踪当前分组的展开状态
  const [isExpanded, setIsExpanded] = useState(false);
  
  // 控制显示的子项:未展开时只显示第一个,展开时显示全部
  const displayedItems = isExpanded ? group.items : group.items.slice(0, 1);

  return (
    <div className={`group-container ${isExpanded ? 'expanded' : ''}`}>
      {/* 分组头部:标题、副标题 + 展开/收起按钮 */}
      <div className="group-header">
        <div className="group-info">
          <h3 className="group-title">{group.title}</h3>
          <p className="group-subtitle">{group.subtitle}</p>
        </div>
        <button 
          className="toggle-btn"
          onClick={() => setIsExpanded(!isExpanded)}
          aria-expanded={isExpanded}
        >
          {isExpanded ? "View Less" : "View All"}
        </button>
      </div>
      
      {/* 子项列表 */}
      <div className="items-list">
        {displayedItems.map((item, idx) => (
          <div key={idx} className="list-item">
            <span className="item-icon">{item.icon}</span>
            <div className="item-details">
              <h4>{item.title}</h4>
              <p className="item-price">{item.price}</p>
              <p className="item-help">{item.helpText}</p>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};
3. Set Up Global Scrolling

Wrap all your groups in a container that allows full-page scrolling. You can either let the browser's default body scrolling handle it, or create a fixed-height scroll container if needed:

const App = () => {
  return (
    <div className="page-wrapper">
      {/* 所有分组都在这里,自然支持全局滚动 */}
      {groupedData.map((group, idx) => (
        <GroupItem key={idx} group={group} />
      ))}
    </div>
  );
};
4. Add Styling for Layout & Transitions

Use CSS to polish the layout and add smooth expand/collapse animations. Here's a basic stylesheet:

/* 全局页面容器 */
.page-wrapper {
  max-width: 1100px;
  margin: 0 auto;
  padding: 2rem 1rem;
  /* 如果需要固定高度的滚动容器,取消下面注释:
  height: 100vh;
  overflow-y: auto;
  */
}

/* 分组容器 */
.group-container {
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  margin-bottom: 1.5rem;
  padding: 1.2rem;
  background-color: #fff;
}

/* 分组头部布局 */
.group-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.group-title {
  margin: 0;
  font-size: 1.3rem;
  color: #2d3748;
}

.group-subtitle {
  margin: 0.3rem 0 0;
  font-size: 0.9rem;
  color: #718096;
}

/* 展开/收起按钮 */
.toggle-btn {
  border: none;
  background: transparent;
  color: #2b6cb0;
  cursor: pointer;
  font-size: 0.9rem;
  padding: 0.3rem 0;
}

.toggle-btn:hover {
  text-decoration: underline;
}

/* 子项列表(带展开动画) */
.items-list {
  max-height: 70px; /* 未展开时的高度,匹配单个子项的高度 */
  overflow: hidden;
  transition: max-height 0.3s ease-in-out;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}

/* 展开时的高度设置为足够大的值 */
.group-container.expanded .items-list {
  max-height: 1000px;
}

/* 单个子项布局 */
.list-item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.8rem;
  background-color: #f7fafc;
  border-radius: 6px;
}

.item-icon {
  font-size: 1.5rem;
}

.item-details h4 {
  margin: 0;
  font-size: 1rem;
  color: #2d3748;
}

.item-price {
  margin: 0.2rem 0;
  font-weight: 600;
  color: #2f855a;
}

.item-help {
  margin: 0;
  font-size: 0.8rem;
  color: #718096;
}
5. Key Optimizations & Extras
  • Performance for large datasets: If you have hundreds of subitems per group, consider using a virtual scrolling library (like react-window or vue-virtual-scroller) to only render items in the viewport—this prevents excessive DOM nodes and keeps scrolling smooth.
  • Accessibility: Add aria-expanded attributes to the toggle button (like in the example) to make the component usable with screen readers.
  • Responsive design: Adjust the layout for mobile (e.g., stack the group header elements vertically) using media queries.

内容的提问来源于stack exchange,提问作者Amira Elsayed Ismail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:32:04