UI页面布局分析(6)- 直播间用户小卡

引言

在现代直播应用中,用户小卡已经成为不可或缺的UI组件。它不仅承载展示用户信息的基础功能,还在主播与观众、观众与观众之间的互动扮演重要角色。一个设计合理、布局高效的用户小卡,可以提升直播间用户体验,同时也有助于增强用户的参与感和归属感。

本篇博客将以直播间内用户小卡为例,从结构组成入手,深入分析其布局设计。随后我们将结合具体代码,探讨如何使用UITableView来实现长页面的布局设计,并分享一些优化技巧,帮助开发者在实际项目中高效实现类似的布局和功能。

用户卡片结构组成

从上图可以看到,直播间内的用户小卡包含了非常丰富的元素。我们可以从上到下将其划分为几个部分进行详细说明:

  1. 1.顶部的操作按钮
    位于小卡左上角的操作按钮,例如举报或设置按钮。

  2. 2.用户基本信息
    显示用户头像、昵称和用户ID,同时根据用户佩戴的徽章显示对应的徽章信息。

  3. 3.用户等级信息
    用户基本信息下方展示用户的等级和经验值,直观地反映用户的活跃程度。

  4. 4.用户年龄、性别、地址与签名信息
    这一部分包含用户的年龄、性别、地址以及个性签名等文本信息。

  5. 5.用户的关注和粉丝数量
    进一步往下,显示用户的关注数量、粉丝数量,以及贡献榜前三名粉丝的信息。

  6. 6.用户的送礼和收礼信息
    在粉丝数量下面,用于展示用户累计收到的金币和送出的礼物总数。

  7. 7.用户的等级、性别及标签徽章
    这一部分集中展示用户的等级标签、性别标签、VIP、SVIP、贵族场控等状态标识,以及用户佩戴的所有徽章信息。

  8. 8.用户达成的成就信息
    显示用户已达成的成就数量,并展示部分成就图标作为代表。

  9. 9.底部操作按钮
    小卡底部的操作栏,包含关注、取消关注、@用户以及发送私信等交互按钮。

  10. 10.小卡背景
    除了上述展示信息与操作按钮外,小卡还配有全屏或半屏高度的背景,用于区分不同用户的卡片类型或身份。

如此多的UI元素,如果直接将所有内容堆叠到一个小卡视图中,代码会变得冗杂且难以维护。更重要的是,如果需要在此基础上增减元素,操作起来将更加复杂。因此,设计一个合理且高效的UI布局方案显得尤为重要。

用户小卡布局分析

根据上面我们对小卡结构组成的分析,我们可以将小卡的布局这样进行分割。

关于用户小卡的全屏背景和半屏背景,我们可以直接使用图片按照设计的比例添加到小卡视图的最低层,不需要考虑任何其它元素,只要覆盖在上面的元素本身没有背景颜色,那么我们总可以看见小卡的背景。

背景之外的部分,我们可以注意到,顶部的操作栏和底部的工具栏是固定在小卡视图的这两个位置,并不会滑动,而其它的所有内容则是在这两个之间,并且随着内容高度高于小卡的高度还会上下滑动,因此我们将小卡的布局首先分为三个部分:

  1. 顶部工具栏:放置设置,举报等按钮,位于小卡视图的最顶端。
  2. 中间信息视图:用来展示所有的用户信息,内容高度不定,可以上下滑动。
  3. 底部工具栏:用户放置关注,@和私信等操作按钮。

关于顶部和底部的工具栏,非常简单都是单一的视图。但就中间的信息视图而言,我们还需要选择一个合适的方式来实现它的布局。由于视图可以上下滑动,所以首先会想到UIScrollView,但是如果使用了UIScrollView我们就需要自己来维护上面子组件的显示和隐藏。所以更理想的选择我们可以使用继承自UIScrollView的UITableView,不同的用户信息视图,就创建不同类型的cell,然后使用数据来控制对应信息cell的显示与隐藏。

用户小卡布局代码实现

接下来我们开始结合具体的代码来分析小卡布局的实现。从小卡背景介绍起,再到顶部工具栏视图,底部工具栏视图,以及中间显示所有用户信息的UITableView。

小卡背景

小卡背景有两种形式,一种是半屏的小卡,只占据用户小卡的顶部的一小部分,另外还有一个全屏的小卡,会占据整个小卡背景。由于它们都不受任何其它子组件的影响,因此我们可以直接着手它们的布局。

    /// 卡片背景图片
    private let bgImageView = UIImageView()
    /// 顶部卡片背景图片
    private let topBgImageView = UIImageView()
    private func setupView() {
        self.backgroundColor = .wm_hex("#1E1E2E")
        self.layer.masksToBounds = true
        self.layer.cornerRadius = 20.0
        // 卡片背景图片
        self.addSubview(bgImageView)
        bgImageView.contentMode = .scaleAspectFill
        // 顶部卡片背景图片
        self.addSubview(topBgImageView)
        topBgImageView.contentMode = .scaleAspectFill
    ....
}
   private func setLayout() {
        // 卡片背景图片
        bgImageView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        // 顶部卡片背景图片
        topBgImageView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
        }
    ....
}
  1. 全屏的背景我们使用bgImageView来显示,它直接充满整个小卡视图。
  2. 而半屏的背景我们使用topBgImageView来显示,它的leading,trailing和top与小卡对其,而高度则会根据内容自动填充。

顶部和底部工具栏

顶部和底部的工具栏,实际上和小卡背景异曲同工,它们都有固定的位置并且不受其它子组件的影响,并且高度固定。

    /// 顶部操作视图
    private let topToolView = MWUserCardTopToolView()
   
    /// 底部操作视图
    private let bottomToolView = MWUserCardBottomToolView()
    private func setupView() {
         ....
        // 顶部操作视图
        self.addSubview(topToolView)
        // 列表
           ...
        // 底部操作视图
        self.addSubview(bottomToolView)
        bottomToolView.backgroundColor = .wm_hex("353543")
    }
    private func setLayout() {
           ...
        // 顶部操作视图
        topToolView.snp.makeConstraints { make in
            make.leading.trailing.top.equalToSuperview()
            make.height.equalTo(48.0)
        }
        // 列表
            ...
        // 底部操作视图
        bottomToolView.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
            make.height.equalTo(44.0)
        }
    }
  1. 顶部工具栏固定在顶部,高度为48。
  2. 底部工具栏固定在小卡底部,高度固定为44。

用户信息列表

用户信息我们采用UITableView来展示,从用户的头像昵称等信息到用户的成就信息,每一个信息视图对应一个类型的cell。为此我们定义了一个数据模型MWBaseRowItem,里面包含了cell的类以及cell标识,具体实现如下:

import UIKit

open class MWBaseRowItem: NSObject {
    
    /// cell标识
    public var cellIdentifier: String = ""
    /// cell类名
    public var cellClass: AnyClass?
    
    public init(cellIdentifier: String, cellClass: AnyClass? = nil) {
        self.cellIdentifier = cellIdentifier
        self.cellClass = cellClass
    }

}

而每一条用户信息都会创建一个对应的MWBaseRowItem实例,放在dataList里,来维护用户信息的一个列表。列表会根据dataList的内容来显示对应类型cell。

dataList构建实现如下:

    /// 构建用户卡片列表数据
    class func buildUserCardListData() -> [MWBaseRowItem] {
        var list = [MWBaseRowItem]()
        //1.头部数据
        let headerItem = MWBaseRowItem(cellIdentifier: NSStringFromClass(MWUserCardHeadInfoCell.self), cellClass: MWUserCardHeadInfoCell.self)
        list.append(headerItem)
        //2.等级
        let levelItem = MWBaseRowItem(cellIdentifier: NSStringFromClass(MWUserCardLevelCell.self), cellClass: MWUserCardLevelCell.self)
        list.append(levelItem)
        //3. 介绍
        let introItem = MWBaseRowItem(cellIdentifier: NSStringFromClass(MWUserCardIntroCell.self), cellClass: MWUserCardIntroCell.self)
        list.append(introItem)
        //4.粉丝/关注数量
        let fansItem = MWBaseRowItem(cellIdentifier: NSStringFromClass(MWUserCardFansCell.self), cellClass: MWUserCardFansCell.self)
        list.append(fansItem)
        //5.金币钻石
        let coinItem = MWBaseRowItem(cellIdentifier: NSStringFromClass(MWUserCardCoinCell.self), cellClass: MWUserCardCoinCell.self)
        list.append(coinItem)
        //6.标签徽章
        let badgeItem = MWBaseRowItem(cellIdentifier: NSStringFromClass(MWUserCardBadgeCell.self), cellClass: MWUserCardBadgeCell.self)
        list.append(badgeItem)
        //7.成就
        let achievementItem = MWBaseRowItem(cellIdentifier: NSStringFromClass(MWUserCardAchievementCell.self), cellClass: MWUserCardAchievementCell.self)
        list.append(achievementItem)
        
        return list
    }

数据里面包含了从用户头像到,用户成就列表的所有数据,以及对应的cell。

下面我们只需要创建一个UITableView并,使用dataList里面的数据来渲染列表即可,实现如下:

    /// 列表
    private let tableView = UITableView(frame: .zero, style: .plain)
   private func setupView() {
        ....
        // 列表
        self.addSubview(tableView)
        tableView.backgroundColor = .clear
        tableView.separatorStyle = .none
        tableView.delegate = self
        tableView.dataSource = self
        for item in dataList {
            tableView.register(item.cellClass, forCellReuseIdentifier: item.cellIdentifier)
        }
        ....
    }
    private func setLayout() {
           ...
        // 列表
        tableView.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview()
            make.bottom.equalToSuperview().offset(-44.0)
            make.top.equalTo(topToolView.snp.bottom)
        }
        ...
    }
  1. 我们根据dataList的数据来注册所有需要用的cell。
  2. 布局时,将顶部工具栏和底部工具栏的位置空出。

接下来在UITableView的代理方法中,我们需要根据dataList中的元素标识,直接返回cell即可:

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = dataList[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: item.cellIdentifier, for: indexPath)
        cell.selectionStyle = .none
        return cell
    }

我们不需要关心cell的类型,也不需要关心该显示那些视图,所有的事情都在数据处理阶段完成了。就算新增新的信息视图,我们只需要创建一个新的cell添加到dataList数组中。如果需要因此某个信息视图,只将对应的数据从dataList数组中移除。

结语

直播间内用户小卡的设计不仅仅是简单的信息展示,更是用户交互体验的关键一环。在这篇博客中,我们从小卡的结构组成入手,分析了其布局设计的重点,并通过代码展示了如何高效实现这样一个复杂的UI组件。

合理的布局不仅能够提升代码的可维护性,还能为后续功能扩展打下坚实的基础。通过模块化的设计思路,我们可以轻松地增减元素,而不影响整体的布局和性能。希望本篇内容能为你在直播应用开发中处理类似的复杂UI需求提供帮助与灵感。

UI设计的每一处细节都值得被精雕细琢,而用户小卡的布局也不例外。如果你在阅读后有任何问题或更好的设计思路,欢迎留言与我交流,共同探索更优雅的实现方式!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值