文章目录
- 这个布局要解决什么问题
- 直接看实现
- 为什么这里适合用 Flex Row
- 容易踩的坑
- 小结
商品列表是移动应用里很常见的场景:左边一张图,中间是标题、标签和价格,右边放一个操作按钮。
这个布局看起来不复杂,但如果全靠Row、Column硬拼,很容易在商品名变长、按钮状态变化、屏幕宽度变小时出现挤压问题。这里我更推荐用Flex({ direction: FlexDirection.Row })来组织外层结构,它的弹性能力更适合这类“固定区域 + 自适应区域”的卡片。
这个布局要解决什么问题
商品卡片通常有三个区域:
- 左侧图片区域:尺寸固定,不能被压缩;
- 中间信息区域:宽度不固定,需要吃掉剩余空间;
- 右侧按钮区域:尺寸固定,点击后要反馈选中状态。
核心思路很直接:外层使用横向Flex,中间信息区设置layoutWeight(1),让它自动占满剩余宽度。这样按钮和图片始终稳定,文本再长也只会在中间区域内截断,不会把右侧按钮挤出去。
直接看实现
这份代码可以直接放进 ArkTS 页面里跑。
/** * Flex Row:商品信息卡片 * 知识点:Flex direction:Row,子项水平排列,图文混排布局 */interfaceGoodsInfo{id:numbername:stringprice:stringoriginalPrice:stringtag:stringtagColor:stringbgColor:string}@Entry@Componentstruct FlexGoodsCardPage{@StateselectedId:number=-1privategoodsList:GoodsInfo[]=[{id:1,name:'无线蓝牙耳机',price:'¥299',originalPrice:'¥599',tag:'限时折扣',tagColor:'#FF4D4D',bgColor:'#FFF5F5'},{id:2,name:'智能运动手表',price:'¥899',originalPrice:'¥1299',tag:'爆款推荐',tagColor:'#FF8C00',bgColor:'#FFF8F0'},{id:3,name:'便携充电宝',price:'¥129',originalPrice:'¥199',tag:'新品上架',tagColor:'#07C160',bgColor:'#F0FFF4'},{id:4,name:'机械键盘',price:'¥459',originalPrice:'¥699',tag:'热销榜一',tagColor:'#007DFF',bgColor:'#F0F7FF'},]build(){Column({space:0}){Row(){Text('商品列表').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#1A1A1A')Blank()Text('查看全部 >').fontSize(14).fontColor('#007DFF')}.width('100%').padding({left:16,right:16,top:20,bottom:12})Column({space:12}){ForEach(this.goodsList,(item:GoodsInfo)=>{Flex({direction:FlexDirection.Row,alignItems:ItemAlign.Center}){Column(){Text(item.name.substring(0,1)).fontSize(28).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)}.width(80).height(80).backgroundColor(item.tagColor).borderRadius(10).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)Column({space:6}){Text(item.name).fontSize(16).fontWeight(FontWeight.Medium).fontColor('#1A1A1A').maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis})Text(item.tag).fontSize(11).fontColor(item.tagColor).backgroundColor(item.bgColor).padding({left:6,right:6,top:2,bottom:2}).borderRadius(4)Row({space:8}){Text(item.price).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#FF4D4D')Text(item.originalPrice).fontSize(13).fontColor('#BBBBBB').decoration({type:TextDecorationType.LineThrough})}}.alignItems(HorizontalAlign.Start).layoutWeight(1).margin({left:14})Button('+').width(36).height(36).fontSize(22).fontColor('#FFFFFF').backgroundColor(this.selectedId===item.id?'#FF4D4D':'#007DFF').borderRadius(18).onClick(()=>{this.selectedId=item.id})}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(14).shadow({radius:8,color:'#1A000000',offsetX:0,offsetY:2}).border({width:this.selectedId===item.id?2:0,color:'#007DFF'})})}.padding({left:16,right:16})}.width('100%').height('100%').backgroundColor('#F5F6FA')}}为什么这里适合用 Flex Row
这张卡片的重点不是“横向排列”这么简单,而是“谁固定、谁自适应”。
左侧图片固定80 x 80,右侧按钮固定36 x 36,中间内容通过layoutWeight(1)吃掉剩余空间。这个结构很适合列表页,因为列表项数量多,数据长度不可控,布局必须稳定。
另外,商品名称用了maxLines(1)和textOverflow,这是列表场景里很实用的兜底。不要指望测试数据永远很短,线上商品名经常比设计稿长很多。
容易踩的坑
如果中间信息区不加layoutWeight(1),它会按内容宽度撑开,右侧按钮就可能被挤压甚至超出屏幕。
如果固定区域没有明确宽高,卡片在不同数据下会出现轻微抖动。商品列表这种高频页面,视觉稳定性比“看起来差不多”更重要。
还有一点,点击状态最好绑定唯一id,不要用数组下标。列表后续如果排序、筛选或分页,下标很容易变,id更稳。
小结
FlexDirection.Row很适合处理图文混排卡片。我的经验是:固定元素明确尺寸,中间内容用layoutWeight(1),长文本加截断,这三件事做好,商品卡片基本就稳了。