UI页面布局分析(7)- 上传相册UI交互的设计方案

引言

在移动应用开发中,UI(用户界面)的设计往往是开发者和设计师的核心关注点。然而,随着功能和交互的复杂性增加,我们往往会遇到一个问题:如何使得UI更加灵活、动态,能够根据不同的数据状态实时更新而无需重复调整界面布局?

传统的UI设计可能会倾向于固定的布局和元素,而这些元素的状态和展示需要通过手动更新来实现。这种方法在开发过程中可能会导致UI逻辑与数据逻辑紧密耦合,增加了维护和扩展的难度。而通过“数据驱动UI”这一方法,UI的展示完全依赖于数据的变化,UI的更新将与数据的状态同步进行。这样,不仅能提高开发效率,还能使得应用的交互更加智能和动态,提升用户体验。

本篇博客将通过一个常见的相册上传功能为例,介绍如何通过数据驱动UI的更新。在这个场景中,我们将通过数据模型来控制界面中上传按钮、图片展示、上传状态等UI元素的显示与变化,而不需要在每次UI更新时手动修改布局。我们将一起探讨如何通过简单的逻辑,确保UI的灵活性和易维护性,同时为用户提供流畅的体验。

需求分析

我们需要做一个如上图所示的相册上传功能,该UI看起来简单清晰,但是如果没有好的实现方案,代码也有可能会变得十分复杂难以维护。我们首先来分析该UI对应的需求。

该UI设计用于展示用户已上传的相册图片,最多显示6个项。若已上传的图片少于6个,则会显示一个添加按钮,用户点击后可以选择多张图片进行上传。上传的图片总数(包括已上传和待上传的图片)不能超过6张。当用户的已上传图片达到6个时,加号按钮将不再显示。每张图片都有不同的状态,包括已上传、正在上传以及上传失败。通过这种方式,用户可以直观地看到上传进度和状态,同时避免上传超过限制。

同时每个图片点击时会根据不同的状态有不同的功能,这个我们可以稍后再讨论。

设计方案

关于UI首选当然还是一个横向滚动的UICollectionView,我们需要关注的重点如何区分加号按钮,以及不同状态的按钮。当获取用户当前相册内容的时候服务端为我们返回了一个数据结构,我们可以以此来创建已上传的用户相册内容的数据模型MWProfileAlbumModel。

public struct MWProfileAlbumModel: Mappable, Equatable {
    /// 大图
    public var srcUrl: String = ""
    /// 小图
    public var littleUrl: String = ""
    
    public init() {
        
    }
    
    public init?(map: Map) {
        
    }
    
    public mutating func mapping(map: Map) {
        srcUrl <- map["srcUrl"]
        littleUrl <- map["littleUrl"]
    }

}

另外我们还需要定义另外一个数据模型MWEditPhotoModel来标记我们需要操作的相册内容。

class MWEditPhotoModel: NSObject {
    
    /// 已上传的 (如果有它,则表示已上传)
    var albumModel:MWProfileAlbumModel?
    /// 是否是+号
    var isAdd:Bool = false
    /// 图片数据
    var image:UIImage?
    /// 上传状态
    var uploadStatus:MWPhotoUploadStatus = .none
}

MWEditPhotoModel是用来决定UI的关键,MWEditPhotoModel包含了已上传的数据模型,同时还标记了是否为加号按钮,待上传的图片数据,以及文件的上传状态。而我们只需要根据这些数据来渲染UICollcectionView列表即可。接下来我们就来一下具体的代码实现。

代码实现

数据模型定义和处理

根据第一部分的需求该我们需要定义图片的最大数据,以及用来渲染用户已经上传的相册数据的列表。并且在接收到列表数据时,来判断是否已经达到了最大值,如果没有达到则为数据添加一个添加按钮数据。

    /// 相册列表数据
    private var editAlbumList: [MWEditPhotoModel] = []
    /// 最大值
    private var maxCount: Int = 6
    /// 渲染数据
    func renderAlbumList(albumList: [MWEditPhotoModel]) {
        editAlbumList = albumList
        // 添加加号按钮
        if albumList.count < maxCount {
            let addModel = MWEditPhotoModel()
            addModel.isAdd = true
            editAlbumList.insert(addModel, at: 0)
        }
        self.collectionView.reloadData()
    }

列表样式渲染

为了显示添加图标,我们需要注册两个不同类型的cell一个用来显示加号,另外一个用来显示图片资源,包括正在上传,上传失败以及已经上传完成的状态。然后根据列表的数据来决定显示何种类型的cell以及cell中图片的上传状态。

    lazy var collectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
        collectionView.backgroundColor = .clear
        // 图片cell
        collectionView.register(MWEditProfileUploadItemCell.self, forCellWithReuseIdentifier: "MWEditProfileUploadItemCell")
        // 上传的cell
        collectionView.register(MWEditPhotoAddCell.self, forCellWithReuseIdentifier: "MWEditPhotoAddCell")
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.showsVerticalScrollIndicator = false
        collectionView.delegate = self
        collectionView.dataSource = self
        return collectionView
    }()
   func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let model = editAlbumList[indexPath.row]
        // 加号cell
        if model.isAdd {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MWEditPhotoAddCell", for: indexPath) as! MWEditPhotoAddCell
            return cell
        }
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MWEditProfileUploadItemCell", for: indexPath) as! MWEditProfileUploadItemCell
        if indexPath.row >= editAlbumList.count {
            return cell
        }
        cell.renderEditPhotoCell(editPhotoModel: model)
        return cell
    }

图片状态渲染

关于加号类型的cell,就不需要过多解释了,只需要将cell的点击事件回传到视图控制器,然后利用系统提供的相册选择功能选择新的照片即可。而关于图片类型cell,我们则需要根据数据的上传状态来渲染不同的样式,比如正在上传,上传失败等等。

    /// 渲染图片cell
    /// - Parameter editPhotoModel: 编辑图片模型
    func renderEditPhotoCell(editPhotoModel: MWEditPhotoModel) {
        coverView.isHidden = true
        loadingIcon.isHidden = true
        reuploadIcon.isHidden = true
        // 请求下来的图片
        if let albumModel = editPhotoModel.albumModel , (editPhotoModel.uploadStatus == .noNeed || editPhotoModel.uploadStatus == .success) {
            let albumUrl = albumModel.littleUrl.validResourceUrl()
            imageView.sd_setImage(with: URL(string: albumUrl))
            return
        }
        // 本地图片
        if let image = editPhotoModel.image {
            imageView.image = image
        }
        if editPhotoModel.uploadStatus == .fail {
            // 上传失败
            coverView.isHidden = false
            reuploadIcon.isHidden = false
        } else if editPhotoModel.uploadStatus == .uploading {
            // 上传中
            coverView.isHidden = false
            loadingIcon.isHidden = false
        }
    }
  1. 对于已经上传完成的数据,我们采用它的远程图片来渲染。
  2. 对刚刚上传的数据,我们采用本地的image来渲染。
  3. 根据模型的上传状态决定选择正在上传的样式还是上传失败的样式。

上传新的图片

当从相册选择完新的一组图片之后,首先根据图片来构建MWEditPhotoModel数据模型,然后执行渲染操作,保证UI显示的是所有内容。然后同时执行上传操作,将整个列表传递到上传方法,方法内部会根据模型的上传状态来区分哪些需要上传,哪些不需要上传。模型会根据上传的结果设置上传状态,当所有模型上传完成之后,在回调中再次刷新列表。

 /// 选择相册图片
    /// - Parameter images: 图片数组
    func uploadAlbum(images: [UIImage]) {
        
            //1. 先刷新
            for image in images {
                let model = MWEditPhotoModel()
                model.image = image
                model.uploadStatus = .none
                editUserPhotos.append(model)
            }
       
        self.tableView.reloadData()
        //2.开始执行上传操作
        self.presenter.requestUploadAlbumData(editPhotoModels: editUserPhotos) {[weak self] in
            guard let self = self else { return }
            self.tableView.reloadData()
        }
    }
  1. 根据选择选择图片数据构建新的数据模型,注意这里的.none表示了需要上传,而执行self.tableView.reloadData()会将editUserPhotos传递到我们定义的相册列表UICollectionView并执行刷新操作。
  2. 开始上传文件,上传完成之后再次给相册列表赋值并刷新UI。

结语

通过这篇博客,我们展示了如何使用数据驱动来实现一个灵活的相册上传功能。借助合理的数据模型设计和动态UI更新,代码不仅清晰易维护,还能带来更好的用户体验。希望这个示例能为你在处理类似问题时提供一些启发,也期待你在自己的项目中探索更多数据驱动UI的可能性!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值