UI页面布局分析(4)- 贵族 特权分页列表

news2025/1/4 12:53:24

引言

在现在移动应用中,展示用户特权的UI设计不仅是吸引用户的关键手段,更是提升产品体验的重要部分。特别是在直播场景中,贵族特权作为一种高价值用户身份的象征,通常需要通过精致的页面和流程的交互来突出其重要性和独特性。

为了实现这种展示效果,开发者面临的不仅仅是美观布局的设计,还需要处理复杂的交互逻辑。例如上面的贵族特权展示页面:

  1. 特权的展示被分为了两个列表,不同列表中的元素大小又不相同。
  2. 而在进行滑动时有需要上下一一对应。
  3. 并且在滑动时还需要让每个特权元素都自动停留在屏幕中间位置。
  4. 另外还有一个特殊效果就是两侧的元素会比中心的元素小上那么一点。

这些效果都对技术实现提出了更高的要求。

本篇博客将以实际项目为例,详细解析贵族特权UI展示效果的设计与实现。从布局分析到交互逻辑的实现,再到细节优化,希望能够为大家实现类似效果提供一些思路。

布局分析

整体结构设计

我们单就贵族页下面的特权展示部分来分析,该部分UI可以分为三个部分:

  1. 首先是最后一层背景,我们可以直接使用UIImageView来实现。
  2. 其次是绿色框的部分,我们需要创建一个自定的视图用来展示贵族特权的小图标列表。
  3. 最后是红色框的部分,我们也来创建一个自定义的视图用来展示贵族特权的大图标和详细信息列表。

分页需求

无论是小的特权图标,还是大的特权卡片都是分页展示的,这就意味着我们创建的滑动视图UIScrollView的isPagingEnabled属性应该为true。而每个列表看上去都是全屏的,如果我们直接设置isPagingEnabled为true显然并不符合要求,所以我们需要按照单个卡片的宽度来进行分页。我们可以通过设置UIScrollView大小为卡片大小的方式并设置UIScrollView的clipsToBounds属性为false来实现这个视觉效果,但是超出部分的触摸事件仍然需要我们手动来处理。

切换效果

当特权卡片进行切换时,它们的切换效果有两个地方需要我们特别注意:

  1. 中间的特权看起来最大,而两侧的特权会随着距离屏幕中心的距离越大看起来越小(有最小值嗷)。
  2. 当滑动上半部分的小特权卡片时,每切换一个卡片,下半部分的特权卡片也会切换一页。而切换下半部分时,上半部分的特权列表也会跟着切换。

具体实现

围绕上述的布局以及需求和动态效果的分析,我们来看一下具体的实现过程,其中切换效果可能是一个难点,但是整个设计的核心还是围绕UISCrollView来实现的。

整体结构实现

我们只考虑贵族页的下半部分特权列表,把注意力集中到一个MWNobleBottomView类当中,在它里面来创建整个特权展示功能。

标题

标题我们采用图片和UILabel结合的方式,放到视图的最顶部,超出视图部分,所以需要将MWNobleBottomView的clipsToBounds属性设置为true。

    /// 渐变横线
    private let lineView = MWGradientView(colors: [.wm_hex("#EDCDAD",0.0),.wm_hex("#EDCDAD"),.wm_hex("#EDCDAD"),.wm_hex("#EDCDAD"),.wm_hex("#EDCDAD",0.0)], direction: .leftToRight)
    /// 标题图标
    private let titleImageView = UIImageView()
    /// 标题
    private let titleLabel = UILabel()
    private func addLineView() {
        self.addSubview(lineView)
        lineView.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview()
            make.centerY.equalTo(self.snp.top)
            make.height.equalTo(1.0)
        }
    }
    
    private func addTitle() {
        self.addSubview(titleImageView)
        titleImageView.image = UIImage(named: "noble_bottom_title")
        titleImageView.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.centerY.equalTo(lineView)
            make.width.equalTo(147.0)
            make.height.equalTo(28.0)
        }
        titleImageView.addSubview(titleLabel)
        titleLabel.textColor = .wm_hex("#F3D39F")
        titleLabel.font = MWFontHelper.font(name: .nunito, size: 16,weight: .bold)
        titleLabel.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
    }

特权小图标列表视图

首先是创建一个特权小图标列表的视图,设置它的约束,并把高度固定:

    /// 小图标列表
    private let smallPricilegesView = MWNobleSmallPricilegesView()
    private func addSmallPricilegesView() {
        self.addSubview(smallPricilegesView)
        smallPricilegesView.backgroundColor = .cyan.withAlphaComponent(0.7)
        smallPricilegesView.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview()
            make.top.equalToSuperview().offset(20.0)
            make.height.equalTo(64.0)
        }
    ....
    }

特权大卡标列表视图

然后是特权大卡片的列表图示,由于也是固定大小,所以我们也可以直接设置高度:

    /// 大图标列表
    private let bigPricilegesView = MWNobleBigPricilegesView()
    private func addBigPricilegesView() {
        self.addSubview(bigPricilegesView)
        bigPricilegesView.backgroundColor = .cyan.withAlphaComponent(0.7)
        bigPricilegesView.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview()
            make.top.equalTo(smallPricilegesView.snp.bottom).offset(20.0)
            make.height.equalTo(311.0 + 42.0)
            make.bottom.equalToSuperview()
        }
    ....
    }

小箭头

别忘了上下对应的小箭头嗷,我们创建一个UIImageView放到合适的位置即可:

    /// 小箭头
    private let smallArrow = UIImageView()
    private func addSmallArrow() {
        self.addSubview(smallArrow)
        smallArrow.image = UIImage(named: "noble_arrow")
        smallArrow.snp.makeConstraints { make in
            make.width.equalTo(28.0)
            make.height.equalTo(13.0)
            make.centerX.equalToSuperview()
            make.top.equalTo(smallPricilegesView.snp.bottom).offset(14.0)
        }
    }

自定义分页实现

关于自定义的分页的实现项目中采用的方案是使用UISCrollView并设置它的宽度与要现实的单个元素视图相同,并设置它的isPagingEnabled为true,同时借助了UIStackView进行布局。

特权小图标列表分页实现

MWNobleSmallPricilegesView

首先创建了一个左右滑动的UISCrollView以及放置在UISCrollView上的UIStackView。

    /// scrollView
    let scrollView = UIScrollView()
    /// UIStackView
    private let stackView = UIStackView()
    private func addScrollView() {
        self.addSubview(scrollView)
        scrollView.clipsToBounds = false
        scrollView.delegate = self
        scrollView.backgroundColor = .clear
        scrollView.isPagingEnabled = true
        scrollView.snp.makeConstraints { make in
            make.top.equalToSuperview()
            make.centerX.equalToSuperview()
            make.width.equalTo(64.0 + 36.0)
            make.height.equalTo(64.0)
        }
    }
    
    private func addStackView() {
        scrollView.addSubview(stackView)
        stackView.backgroundColor = .clear
        stackView.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.height.equalTo(64.0)
            make.leading.equalToSuperview()
            make.trailing.equalToSuperview()
        }
        stackView.axis = .horizontal
        stackView.spacing = 0.0
    }

这里需要注意它的宽度和高度,宽度为单元视图宽度+单元视图之间的间距。而高度固定为64。

这么设置之后,UIScrollView会显示全屏的宽度,但是可操作的部分仍然只有64.0+36.0。

接下来我们需要重写系统的hitTest方法,将响应事件转移到UIScrollView上,来保证它的可操作部分与可见部分一致:

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let view = super.hitTest(point, with: event)
        if view == self {
            return scrollView
        }
        return view
    }

特权大卡片列表分页实现

MWNobleBigPricilegesView

大卡列表片实现自定义分页的图标与小图标实现的思路完全相同,我们将UIScrollView设置为固定的宽度,并且将滑动事件扩大到整个屏幕宽。

    /// scrollView
    let scrollView = UIScrollView()
    /// UIStackView
    private let stackView = UIStackView()
    private func addScrollView() {
        self.addSubview(scrollView)
        scrollView.clipsToBounds = false
        scrollView.delegate = self
        scrollView.backgroundColor = .clear
        scrollView.isPagingEnabled = true
        scrollView.snp.makeConstraints { make in
            make.top.equalToSuperview()
            make.centerX.equalToSuperview()
            make.width.equalTo(277.0 + 23.0)
            make.height.equalTo(331.0)
        }
    }
    
    private func addStackView() {
        scrollView.addSubview(stackView)
        stackView.backgroundColor = .clear
        stackView.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.height.equalTo(331.0)
            make.leading.equalToSuperview()
            make.trailing.equalToSuperview()
        }
        stackView.axis = .horizontal
        stackView.spacing = 0.0
    }
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let view = super.hitTest(point, with: event)
        if view == self {
            return scrollView
        }
        return view
    }
  

切换效果实现

我们根据数据在特权列表创建对一个的单元视图,并且设置每个视图的缩放比例来保证视图的起始视觉效果。而要实现视图的切换视觉效果,我们就不得不实现UIScrollViewDelegate协议中的scrollViewDidScroll方法,通过计算每个单元视图距离视图中心的距离,来设置不同的缩放比例。

特权小图列表切换效果实现

我们先来看一下特权小图切换效果的实现,首先根据数据创建列表视图,因为特权的数据较少,所以在这个例子中我们将视图平铺到了UISCrollView。

并将从第二个开始的视图按比例缩小。

    /// 渲染数据
    /// - Parameter nobleConfigModel: 贵族配置
    /// - Parameter nobleInfoModel: 贵族信息
    func renderData(nobleConfigModel:MWMineNobleConfigModel,nobleInfoModel:MWNobleInfoModel) {
        let nobleItemList = nobleConfigModel.nobleItemList
        for i in 0..<nobleItemList.count {
            let itemView = MWNobleSmallPricilegesItemView()
            stackView.addArrangedSubview(itemView)
            let model = nobleItemList[i]
            let icon_url =  model.indicatorUrl
            let url = URL(string: icon_url.validResourceUrl())
            itemView.imageView.sd_setImage(with: url)
            itemView.tag = 100 + i
            itemView.snp.makeConstraints { make in
                make.width.height.equalTo(36.0 + 64.0)
            }
            if i != 0 {
                let maxScaleFactor: CGFloat =  54.0/64.0
                itemView.transform = CGAffineTransform(scaleX: maxScaleFactor, y: maxScaleFactor)
            }
        }
    }

当UIScrollView开始滑动时,重新设置视图中的所有视图缩放比例。

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
         ...
        startScale()
    }
   /// 开始缩放
    @objc private func startScale() {
        for view in stackView.arrangedSubviews {
            scaleItemView(view as! MWNobleSmallPricilegesItemView)
        }
    }
    
    private func scaleItemView(_ itemView: MWNobleSmallPricilegesItemView) {
        let distanceFromCenter = abs(itemView.center.x - scrollView.contentOffset.x - scrollView.bounds.width / 2)
        let maxScaleFactor: CGFloat = 1.0 // 最近时的缩放比例
        let minScaleFactor: CGFloat = 54.0 / 64.0 // 最远时的缩放比例
        let scaleRange = maxScaleFactor - minScaleFactor
        
        // 距离越远,缩放越接近 minScaleFactor
        let scaleFactor = max(minScaleFactor, maxScaleFactor - (distanceFromCenter / scrollView.bounds.width) * scaleRange)
        itemView.transform = CGAffineTransform(scaleX: scaleFactor, y: scaleFactor)
    }

特权大卡列表切换效果实现

大卡列表的实现思路与小卡完全相同,也是在赋值时添加卡片,而滑动时开始设置每一张卡片的缩放比例,只是比例不同,具体实现如下:

    /// 渲染数据
    /// - Parameter nobleConfigModel: 贵族配置
    /// - Parameter nobleInfoModel: 贵族信息
    func renderData(nobleConfigModel:MWMineNobleConfigModel,nobleInfoModel:MWNobleInfoModel) {
        let nobleItemList = nobleConfigModel.nobleItemList
        for i in 0..<nobleItemList.count {
            let model = nobleItemList[i]
            let itemView = MWNobleBigPricilegesItemView()
            stackView.addArrangedSubview(itemView)
            itemView.titleLabel.text = model.rightName
            itemView.descLabel.text = model.rightDesc
            let portraits = model.portrait
            /// 示例图标
            let index = nobleConfigModel.nobleLevel - 1
            if index < portraits.count {
                let portrait = portraits[index]
                let url = URL(string: portrait.validResourceUrl())
                itemView.exampleImageView.sd_setImage(with: url)
            }
            itemView.tag = 100 + i
            itemView.snp.makeConstraints { make in
                make.width.equalTo(277.0 + 23.0)
                make.height.equalTo(311.0)
            }
            if i != 0 {
                let maxScaleFactor: CGFloat = 262.0/311.0
                itemView.transform = CGAffineTransform(scaleX: maxScaleFactor, y: maxScaleFactor)
            }
        }
    }
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        ...
        startScale()
    }
    
    /// 开始缩放
    @objc private func startScale() {
        for view in stackView.arrangedSubviews {
            scaleItemView(view as! MWNobleBigPricilegesItemView)
        }
    }
    
    /// 缩放itemView
    private func scaleItemView(_ itemView: MWNobleBigPricilegesItemView) {
        let distanceFromCenter = abs(itemView.center.x - scrollView.contentOffset.x - scrollView.bounds.width / 2)
        let maxScaleFactor: CGFloat = 1.0 // 最近时的缩放比例
        let minScaleFactor: CGFloat = 262.0 / 311.0 // 最远时的缩放比例
        let scaleRange = maxScaleFactor - minScaleFactor
        
        // 距离越远,缩放越接近 minScaleFactor
        let scaleFactor = max(minScaleFactor, maxScaleFactor - (distanceFromCenter / scrollView.bounds.width) * scaleRange)
        itemView.transform = CGAffineTransform(scaleX: scaleFactor, y: scaleFactor)
    }

切换联动实现

为了实现联动的效果,首先我们需要将每个列表的滑动事件都回调到外面,并同步到另外一个列表。

但是在列表滑动时,当小列表切换一页对应的大卡列表也应该切换一页,因此我们需要将视图的偏移量做一个定比例的映射。

大卡列表UIScrollView滑动的回调

class MWNobleBigPricilegesView: UIView,UIScrollViewDelegate {
    
     ....
    /// scrollView滑动的回调(带x偏移量)
    var scrollViewDidScrollBlock: ((CGFloat) -> Void)?
    ...

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if let block = scrollViewDidScrollBlock {
            block(scrollView.contentOffset.x)
        }
        ....
    }
    
}

然后大卡列表滑动的回调中来使小图列表被动更新UISCrollView的contentoffsetx:

    private func addBigPricilegesView() {
         ...
        bigPricilegesView.scrollViewDidScrollBlock = { [weak self] x in
            self?.smallPricilegesView.scrollView.contentOffset.x = x * 100.0 / 300.0
        }
    }

小图列表UIScrollView滑动回调

class MWNobleSmallPricilegesView: UIView,UIScrollViewDelegate {
    
     ...
    var scrollViewDidScrollBlock: ((CGFloat) -> Void)?
    /// 选中的index回调
    var didSelectIndexBlock: ((Int) -> Void)?
    /// 当前页
    private var currentIndex = 0
    ...
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if let block = scrollViewDidScrollBlock {
            block(scrollView.contentOffset.x)
        }
        if let block = didSelectIndexBlock {
            let index = Int(scrollView.contentOffset.x / scrollView.bounds.width)
            if index != currentIndex {
                block(index)
                currentIndex = index
            }
        }
    ....
    }
}
  

小图列表里面除了滑动的回调之外,我们还定义了一个页切换的回调用来同步标题。

接下来我们就需要在小图列表滚动的回调中设置大卡列表的偏移量,以及标题:

    private func addSmallPricilegesView() {
        ....
        smallPricilegesView.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview()
            make.top.equalToSuperview().offset(20.0)
            make.height.equalTo(64.0)
        }
        smallPricilegesView.scrollViewDidScrollBlock = { [weak self] x in
            self?.bigPricilegesView.scrollView.contentOffset.x = x * 300.0 / 100.0
        }
        // 切面切换
        smallPricilegesView.didSelectIndexBlock = { [weak self] index in
            guard let self = self else { return }
            if let nobleConfigModel = self.nobleConfigModel {
                let count = nobleConfigModel.nobleItemList.count
                if count == 0 {
                    return
                }
                self.titleLabel.text = MWLocaleStringHelper.getString("Privileges") + "\(index+1)/\(count)"
            }
        }
    }

最终效果如下:

结语

通过本篇博客,我们详细解析了贵族特权 UI 展示效果的实现,包括布局设计、分页逻辑、自定义切换效果以及上下部分的联动处理。这些技术点不仅展示了如何实现特定的界面效果,也体现了在复杂需求下平衡性能与交互体验的思路。

尽管这种布局设计是为特定场景量身定制的,但其实现思路与技巧,如非全屏分页的处理、自定义动画效果以及视图联动逻辑,或许可以为你的项目提供新的思路和启发。希望这篇文章能够帮助你更灵活地应对类似的 UI 实现需求。

如果你在实现过程中遇到任何问题,欢迎随时留言交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络实验室建设方案

一、计算机网络实验室拓扑结构 计算机网络综合实验室解决方案&#xff0c;是面向高校网络相关专业开展教学实训的综合实训基地解决方案。教学实训系统采用 B&#xff0f;S架构&#xff0c;通过公有云教学实训平台在线学习模式&#xff0c;轻松实现网络系统建设与运维技术的教学…

D类音频应用EMI管理

1、前言 对于EMI&#xff0c;首先需要理解天线。频率和波长之间的关系&#xff0c;如下图所示。   作为有效天线所需的最短长度是λ/4。在空气中&#xff0c;介电常数是1&#xff0c;但是在FR4或玻璃环氧PCB的情况下&#xff0c;介电常数大约4.8。这种效应会导致信号在FR4材…

若依框架之简历pdf文档预览功能

一、前端 &#xff08;1&#xff09;安装插件vue-pdf&#xff1a;npm install vue-pdf &#xff08;2&#xff09;引入方式&#xff1a;import pdf from "vue-pdf"; &#xff08;3&#xff09;components注入方式&#xff1a;components:{pdf} &#xff08;4&…

lua-debug for Sublime

目标 Sublime 也支持 lua-debug&#xff0c;操作体验与 VSCode 一致。 优势 执行效率高&#xff0c;不掉帧 可随时开启 配置简单&#xff0c;一份配置兼容 VSCode 和 Sublime 安装 要求 Sublime 4 的版本&#xff08;注&#xff1a;从 Sublime 3 升到 4 的不算&#xff0c;…

手机h5加桌面图标

手机h5应用1&#xff0c;网址浏览器添加到桌面&#xff0c;修改图标 关键代码 <!-- 手机h5加桌面图标 --> <!-- 安卓平台 chrome --> <link relapple-touch-icon-precomposed href<% BASE_URL %>logonew.png> <meta name"mobile-web-app-capab…

开发场景中Java 集合的最佳选择

在 Java 开发中&#xff0c;集合类是处理数据的核心工具。合理选择集合&#xff0c;不仅可以提高代码效率&#xff0c;还能让代码更简洁。本篇文章将重点探讨 List、Set 和 Map 的适用场景及优缺点&#xff0c;帮助你在实际开发中找到最佳解决方案。 一、List&#xff1a;有序存…

acitvemq AMQP:因为消息映射策略配置导致的MQTT接收JMS消息乱码问题 x-opt-jms-dest x-opt-jms-msg-type

使用ActiveMQ&#xff08;5.14.5&#xff09;作消息系统服务的场景下&#xff0c; 当我用Apache Qpid Proton发送消息(使用AMQP协议)发送JMS消息&#xff0c;用Paho MQTT接收消息的时候&#xff0c; 收到的消息前面总是有一串乱码&#xff0c;大概就是这样&#xff1a; 4Sp?AS…

apisix的hmac-auth认证

目录 1、apisix的hmac认证Authorization头信息 2、signature的lua生成源码 3、java生成签证的简单示例 4、postman调用如下 apisix的hmac-auth认证&#xff0c;介绍可以看官方文档 hmac-auth | Apache APISIX -- Cloud-Native API Gateway 照着官方文档&#xff0c;发现生…

Webpack在Vue CLI中的应用

webpack 作为目前最流行的项目打包工具&#xff0c;被广泛使用于项目的构建和开发过程中&#xff0c;其实说它是打包工具有点大材小用了&#xff0c;我个人认为它是一个集前端自动化、模块化、组件化于一体的可拓展系统&#xff0c;你可以根据自己的需要来进行一系列的配置和安…

uniapp 前端解决精度丢失的问题 (后端返回分布式id)

原因&#xff1a; 后端使用分布式id, id为19位数&#xff0c;导致精度丢失 &#xff0c;前端解决方法 这个是通过浏览器请求回来的数据&#xff0c;这个时候id 数据已经丢失了&#xff0c;在数据库查询不到&#xff0c;在调获详情接口的时候会有问题 实际的&#xff1a; 解决…

外网访问 Docker 容器的可视化管理工具 DockerUI

DockerUI 是一个 docker 容器镜像的可视化图形化管理工具&#xff0c;DockerUI 可以用来轻松构建、管理和维护 docker 环境。让用户维护起来更方便。 本文就介绍如何安装使用 DockerUI 并结合路由侠内网穿透来访问 DockerUI。 第一步&#xff0c;安装 DockerUI 1&#xff0c;…

Docker安装和使用RabbitMQ

Docker安装和使用RabbitMQ 1、拉取镜像2、运行Docker容器3、控制台界面 1、拉取镜像 docker pull rabbitmq:3-management2、运行Docker容器 docker run \-e RABBITMQ_DEFAULT_USERjagochan \-e RABBITMQ_DEFAULT_PASSjagochan \--name mq \--hostname mq \-p 15672:15672 \-p…

STM32F103RCT6学习之五:ADC

1.ADC基础 ADC&#xff08;Analog-Digital Converter&#xff09;模拟-数字转换器ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁12位逐次逼近型ADC&#xff0c;1us转换时间 输入电压范围&#xff1a;0~3.3V&#xff…

Python学习(2):注释、数字、文本、列表

1 关于注释 Python 使用井号#作为单行注释的符号&#xff0c; 使用三个连续的单引号’’或者三个连续的双引号"""注释多行内容。 2 数字 2.1 基本运算 解释器像一个简单的计算器&#xff1a;你可以输入一个表达式&#xff0c;它将给出结果值。 表达式语法很直观…

【Maven_bugs】The project main artifact does not exist

背景&#xff1a;我想使用 maven-shade-plugin 打一个 fat jar 时报了标题中的错误&#xff0c;使用的命令是&#xff1a;org.apache.maven.plugins:maven-shade-plugin:shade -pl :shade-project。项目结构如下图&#xff0c;我想把子模块 shade-project 打成一个 fat jar&…

Wordperss漏洞 DeDeCMS漏洞

Wordperss漏洞 环境搭建 #执⾏命令 cd /vulhub/wordpress/pwnscriptum docker-compose up -d #靶场地址 http://8.155.7.173:8080/wp-admin/ 注册账号 登录 漏洞一&#xff1a;后台修改模板拿WebShell 步骤一&#xff1a;思路是修改其WP的模板写入⼀句话木马后门并访问其文件…

使用 HTML 和 CSS 实现绚丽的节日烟花效果

文章目录 1. 效果预览2. 核心技术栈3. 核心代码解读3.1 HTML结构3.2 霓虹文字的CSS样式3.2.1 核心样式代码3.2.2 动画效果 3.3 JavaScript 的烟花效果实现3.3.1 烟花上升3.3.2 粒子爆炸 4. 用户交互5. 运行步骤总结 1. 效果预览 打开后输入文本的展示内容 用户点击页面后播放…

电力场景输电线路异物检测数据集VOC+YOLO格式4370张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4370 标注数量(xml文件个数)&#xff1a;4370 标注数量(txt文件个数)&#xff1a;4370 …

【Next.js】002-路由篇|App Router

【Next.js】002-路由篇|App Router 文章目录 【Next.js】002-路由篇|App Router一、前言二、文件系统&#xff08;file-system&#xff09;1、说明2、演练创建代码运行访问让 Cursor 分析错误别偷懒&#xff0c;还是探究一下 Pages Router 方式吧创建代码运行并访问项目/about …

【FPGA开发】ZYNQ中PS与PL交互操作总结、BRAM,DMA原理浅析、仿真操作

文章目录 PL与PS交互综述交互端口性能&特点&#xff08;选择方案的凭据&#xff09;GPIO-AXI_GPDMA-DMACHP-AXI_HPACP-AXI_ACP 数据交互实验GP通过BRAMPS为主机&#xff0c;读写BRAMPL作为主机&#xff0c;读写BRAM DMA方式交互 PL与PS交互综述 网络上关于PS PL交互的教程…