如何用 Swift 编写滑出式导航面板

原文:How to Create Your Own Slide-Out Navigation Panel in Swift
作者:Nicholas Sakaimbo
译者:kmyhy

更新说明:本教程由 Nick Sakaimbo 更新为 iOS 11、Xcode 9 和 Swift 4。原文作者是 Tammy Coron。

本文介绍如何编写一个滑出式导航面板,这是用于替代 UINavigationController 和 UITabBarController 的一种主流做法,它允许用户内容切入/切出屏幕。

滑出式导航面板这样的设计模式允许开发者在不占用宝贵屏幕空间的情况下为 app 增加一种固定的导航方式。用户可以在任何时候显示这个导航,同时不用隐藏当前显示内容

在本文,你会用一种“越少越好”的方式将滑动式导航面板轻松地应用到你自己的 app 中。

开始

你将在一个漂亮的猫咪/狗狗图片浏览器中编写这个滑动式导航面板。首先,请下载这个开始项目。这是一个 zip 文件,请保存后解压缩。

然后打开项目,看一下项目结构。Assets 文件夹是一些 asset catalogs,全都是 app 中用于显示的猫狗图片。注意有 3 个主要的 view controller。如果你要将这个教程用到自己的项目中,请注意它们:

  • ContainerViewController: 奇迹将在这里发生!它包含了一个左、中、右的视图,负责处理动画和滑动手势。在这个项目中,它是在 AppDelegate.swift 的application(_:didFinishLaunchingWithOptons:) 方法中被创建和添加到 window 的。
  • CenterViewController: 中间面板。你可以用自己的 view controller(确保你复制了按钮的 action) 来替换它。
  • SidePanelViewController: 左、右面板。也可以用你自己的 view controller 进行替换。

这 3 个 view controller 的视图在 Main.storyboard 中定义,请自行查看以便了解 app 的大致模样。

熟悉完项目的结构,来看看中间面板。

找到你的中心

在这节,你将以子控制器的形式将 CenterViewcontroller 放到 ContainerViewcontroller 中。

注意:这里使用了 iOS 5 中的视图控制器容器的概念。如果你不熟悉,请阅读 iOS 5 by Tutorials 第 22 章“UIViewController 容器”。

打开 ContainerViewController.swift。在文件底部,有一个扩展,用于 UIStoryboard。它添加了几个静态方法,用于简化从 storyboard 中加载某个 view controller 的过程。你等会会用到这些方法

为 ContainerViewController 添加几个属性,用于保存一个 CenterVierController 和一个 UINavigationController 对象:

var centerNavigationController: UINavigationController!
var centerViewController: CenterViewController!

注意:这里使用了隐式解包(注意 !的使用)。它们肯定是可空的,因为当 init() 方法调用时它们还不会被初始化,但它们会进行自动解包,因为当它们被创建时你能够确保它们总是会有值的。

然后,在 viewDidLoad() 的 super 调用之后添加

centerViewController = UIStoryboard.centerViewController()
centerViewController.delegate = self

// wrap the centerViewController in a navigation controller,so we can push views to it
// and display bar button items in the navigation bar
centerNavigationController = UINavigationController(rootViewController: centerViewController)
view.addSubview(centerNavigationController.view)
addChildViewController(centerNavigationController)

centerNavigationController.didMove(toParentViewController: self)

上述代码创建了一个新的 CenterViewController 并将它保存到 centerViewController 属性。然后创建了一个 UINavigationController 用于包含这个 center view controller。然后将 navigation controller 的 view 添加到 ContainerViewController 的 view,并调用 addChildViewController(_:) 和 didMove(toParentViewController:) 方法建立二者的父子关系。

同时也将当前 view controller 设置为 center view controller 的委托。 center view controller 会问当前 view controller 何时显示和隐藏左右面板。

如果现在编译,你会看到在设置 delegate 一句处报错。你必须修改这个类,让它实现 CenterViewControllerDelegate 协议。添加一个扩展来实现这个协议。在 UIStoryboard 扩展后添加(有一些空方法,我们后面实现它们):

// MARK: CenterViewController delegate

extension ContainerViewController: CenterViewControllerDelegate {

  func toggleLeftPanel() {
  }

  func toggleRightPanel() {
  }

  func addLeftPanelViewController() {
  }

  func addRightPanelViewController() {
  }

  func animateLeftPanel(shouldExpand: Bool) {
  }

  func animateRightPanel(shouldExpand: Bool) {
  }
}

来检验一下成果。Build & run。如果一切正常,你会看到:

顶部按钮最终会打开猫咪的图片或者狗狗的图片。那为什么还要创建一个滑出式导航面板呢?仅仅是为了看起来好看,你必须实现滑动式。首先,从左边开始!

猫咪们到左边来…

你创建了你的中间面板,但添加左边的 View controller 是不同的一个步骤。这个过程稍有点多,请务必耐心。多想想猫咪们吧!

要展开左侧菜单用户需要点击 Kitties 按钮。因此请打开 CenterViewController.swift。

为了将精力集中在重要的事情上,IBAction 和 IBOutlet 在 storyboard 已经是建好的了。但是,如果要实现你自己的滑出式导航面板,你必须理解这些按钮是如何被设置的。

注意已经有两个 IBAction 方法了,一个方法针对一个按钮。找到 kittiesTapped(_:) 方法添加代码

delegate?.toggleLeftPanel?()

前面提过,这个方法连接到了 Kitties 按钮。

一个可空链使得只有在 delegate 不为空且 toggleLeftPanel 方法已经实现的情况下才会调用 toggleLeftPanel 方法

你可以在 CenterViewControllerDelegate.swift 中看一下委托协议的定义。你会看到,有两个 optional 方法 toggleLeftPanel() 和 toggleRightPanel()。还记得吧,在你创建 center view controller 实例时,你将它的 delegate 设置为 container view controller。接下来我们就实现 toggleLeftPanel()。

注意:关于委托方法和如何实现它们的内容,请参考苹果的开发文档。

打开 ContainerViewController.swift。首先,声明一个枚举。在类名之下添加

class ContainerViewController: UIViewController {

  enum SlideOutState {
    case bothCollapsed
    case leftPanelExpanded
    case rightPanelExpanded
  }

// ...

这个枚举用于保存侧面板的当前状态,你可以用它们表示任何一个面板都不可见,或者左右面板中有一个可见。

然后,在 centerViewController 属性添加两个属性

var currentState: SlideOutState = .bothCollapsed
var leftViewController: SidePanelViewController?

分别用于保存当前状态,以及左侧的 view controller:

一开始的初始状态认为 .bothCollapsed——也就是说两个侧面板都不可见。leftViewController 属性一个可空类型,因为你会在不同的时候添加和移除这个 view controller,因此它有可能有时候是没有值的。

接着,实现 toggleLeftPanel() 委托方法

let notAlreadyExpanded = (currentState != .leftPanelExpanded)

if notAlreadyExpanded { addLeftPanelViewController() }

animateLeftPanel(shouldExpand: notAlreadyExpanded)

首先,这个方法会检查左面板是否已经展开。如果它未显示,就将面板添加到视图树中,并将其动画到’打开’的位置。如果这个面板已经显示,它则将它动画到’关闭’位置。

然后,用下面的代码将左面板添加到视图树中。找到 addLeftPanelViewController() 方法,在里面添加代码

guard leftViewController == nil else { return }

if let vc = UIStoryboard.leftViewController() {
  vc.animals = Animal.allCats()
  addChildSidePanelController(vc)
  leftViewController = vc
}

这段代码首先检查 leftViewController 属性是否为 nil。如果是,创建一个新的 SidePanelViewController,然后设置它的 animals 数组,也就是要显示的数据——猫咪们!

然后在 addLeftPanelViewController() 下面添加 addChildSidePanelController() 方法

func addChildSidePanelController(_ sidePanelController: SidePanelViewController) {

  view.insertSubview(sidePanelController.view,at: 0)

  addChildViewController(sidePanelController)
  sidePanelController.didMove(toParentViewController: self)
}

这个方法用于向 container view controller 中添加子 view。这个过程和前面添加 cener view controller 是一样的。首先插入它的 view(这里将插入的 z 位置设置为 0,这样它就会位于 center view controller 的下面),然后添加子控制器。

基本上可以运行项目了,但还有一个事情要做添加动画!它不需要多少时间!

说好的滑滑滑滑动呢?

首先,在 ContainerViewController 中添加一个常量:

let centerPanelExpandedOffset: CGFloat = 60

这是center view controller 滑开后还有多少像素宽度可见,设置为 60。

接着,找到 animateLeftPanel(shouldExpand:) 方法添加代码

if shouldExpand {
  currentState = .leftPanelExpanded
  animateCenterPanelXPosition(
    targetPosition: centerNavigationController.view.frame.width - centerPanelExpandedOffset)

} else {
  animateCenterPanelXPosition(targetPosition: 0) { finished in
    self.currentState = .bothCollapsed
    self.leftViewController?.view.removeFromSuperview()
    self.leftViewController = nil
  }
}

这个方法简单地判断侧边面板是要展开还是隐藏。如果是展开,设置 currentState 属性为展开,让中间面板移动以成为“打开”状态。相反,它会让中间面板动画到“关闭”位置,并移除视图,将当前状态置为关闭状态。

最后,在 animatedLeftPanel(shouldExpand:) 方法后面添加animateCenterPanelXPosition(targetPosition:completion:) 方法

func animateCenterPanelXPosition(targetPosition: CGFloat,completion: ((Bool) -> Void)? = nil) {

  UIView.animate(withDuration: 0.5,delay: 0,usingSpringWithdamping: 0.8,initialSpringVeLocity: 0,options: .curveEaseInOut,animations: {
      self.centerNavigationController.view.frame.origin.x = targetPosition
    },completion: completion)
  }

这是真正放动画代码的地方。中间控制器的 view 被动画到指定位置,带有弹簧动画效果。这个方法也带一个可控的完成闭包,用于传递给 UIView 动画的 animate 方法。如果你想修改动画的效果,可以调整动画时长和弹簧动画的阻尼系数。

好了……是时候来试试看了,可以 Build & run 一下了。动手吧!

运行 app 时,点击 Kitties 按钮。中间控制器会滑动——刷!——然后露出底下的 Kitties 菜单。噢,看起来好棒。

太可爱了,真是受不了!再次点击 Kitties 按钮,又可以隐藏菜单

我和影子

当左面板打开时,它正好在中间视图控制器上面。如果让两者之间有一个明显区分将是个不错的事情。可以加一个阴影吗?

若日后是 ContainerViewController,添加方法

func showShadowForCenterViewController(_ shouldShowShadow: Bool) {

  if shouldShowShadow {
    centerNavigationController.view.layer.shadowOpacity = 0.8
  } else {
    centerNavigationController.view.layer.shadowOpacity = 0.0
  }
}

通过修改导航控制器的 shadowOpacity 属性显示显示阴影。你可以用 currentState 属性的 didSet 属性观察器来添加删除这个阴影。

扎到 ContentViewController 的 currentState 定义,将它修改为:

var currentState: SlideOutState = .bothCollapsed {
  didSet {
      let shouldShowShadow = currentState != .bothCollapsed
      showShadowForCenterViewController(shouldShowShadow)
    }
}

在 didSet 闭包中,当属性值被改变时,调用上个方法。无论哪一个面板被打开,都显示它们的阴影。

Build & run。当你点击 Kitties 按钮,注意可爱的阴影!这样效果更好,不是吗?

接下来,实现同样的功能,但这次是针对右边栏,也就是……狗狗们!

狗狗们到右边来……

添加右面板视图控制器的方法,和添加左面板的视图控制器一模一样。

打开 ContainerViewController.swift,在 leftViewController 下增加一个属性

var rightViewController: SidePanelViewController?

然后找到 toggleRightPanel() 方法添加代码

let notAlreadyExpanded = (currentState != .rightPanelExpanded)

if notAlreadyExpanded { addRightPanelViewController() }
animateRightPanel(shouldExpand: notAlreadyExpanded)

接着,将 addRightPanelViewController() 和 animateRightPanel(shouldExpand:) 方法修改为:

func addRightPanelViewController() {

  guard rightViewController == nil else { return }

  if let vc = UIStoryboard.rightViewController() {
    vc.animals = Animal.allDogs()
    addChildSidePanelController(vc)
    rightViewController = vc
  }
}

func animateRightPanel(shouldExpand: Bool) {

  if shouldExpand {
    currentState = .rightPanelExpanded
    animateCenterPanelXPosition(
      targetPosition: -centerNavigationController.view.frame.width + centerPanelExpandedOffset)

  } else {
    animateCenterPanelXPosition(targetPosition: 0) { _ in
      self.currentState = .bothCollapsed

      self.rightViewController?.view.removeFromSuperview()
      self.rightViewController = nil
    }
  }
}

这些代码基本上和之前左面板实现的方法一样,只不过方法名和属性名以及动画方向不同。如果你对此有疑问,请参考上一节的解释。

和之前一样,IBActions 和 IBOultets 已经建立了连接。和 Kitties 按钮一样,Puppies 按钮连接到 IBAction 方法 puppiesTapped(_:)。这个按钮能够将中间的面板滑开显示出右边的面板。

最后,回到 CenterViewController.swift 在 puppiesTapped(_:) 中添加代码

delegate?.toggleRightPanel?()

这和 kittiesTapped(_:) 还是一样,只不过 toggleLeftPanel 变成了 toggleRightPanel。

来看一下狗狗们吧!

Build & run,点击 Puppies 按钮,你会看到:

开起来不错,是吧?记住不要让你自己在这些可爱的狗狗面前呆得太长哦,现在再次点击按钮关闭它。

你现在既可以查看猫咪也可以查看狗狗了,但能够查看它们的大图岂不更爽?:]

一个宠物吧

狗狗和猫咪们分别显示在右面板和左面板中,这是两个 SidePanelViewController 实例,实际上就只包含了 table view 而已。

回到 SidePanelViewControllerDelegate.swift 看一眼 SidePanelViewController 的委托方法。当某个宠物被选中时,委托对象的这个方法会被调用。我们可以利用它!

在 SidePanelViewController.swift 中,在 tableView 属性添加一个可空的 delegate 属性

var delegate: SidePanelViewControllerDelegate?

然后在 UITableViewDelegate 扩展的 tableView(_:didSelectRowAt:) 方法中:

func tableView(_ tableView: UITableView,didSelectRowAt indexPath: IndexPath) {
  let animal = animals[indexPath.row]
  delegate?.didSelectAnimal(animal)
}

如果 delegate 不为空,就通知 delegate 某个宠物被选中了。但是现在委托对象都还没有呢!可以用 CenterViewController 作为 side panel 的委托,因为可以用来显示所选宠物的图片标题

打开 CenterViewController.swift 实现委托协议。添加一个扩展:

extension CenterViewController: SidePanelViewControllerDelegate {

  func didSelectAnimal(_ animal: Animal) {
    imageView.image = animal.image
    titleLabel.text = animal.title
    creatorLabel.text = animal.creator

    delegate?.collapseSidePanels?()
  }
}

这个方法简单地在中间视图控制器中渲染了图片标签。然后,如果中间视图控制器也有一个委托的话,就告诉它收起 side panel,以便你能够看到所选的宠物。

collapseSidePanels()还没实现。打开 ContainerViewController.swift 在 toggleRightPanel() 下加入:

func collapseSidePanels() {

  switch currentState {
    case .rightPanelExpanded:
      toggleRightPanel()
    case .leftPanelExpanded:
      toggleLeftPanel()
    default:
        break
  }
}

该 switch 语句判断当前状态,如果发现有打开着的 side panel 就关闭它。

最后,将 addChildSidePanelViewController(_:) 修改为:

func addChildSidePanelController(_ sidePanelController: SidePanelViewController) {
  sidePanelController.delegate = centerViewController
  view.insertSubview(sidePanelController.view,at: 0)

  addChildViewController(sidePanelController)
  sidePanelController.didMove(toParentViewController: self)
}

除了之前的代码,还将 center view controller 设置为 side panel 的 delegate。

就是这样了!Build & run。查看 Kitties 或者 Puppies,点击其中的某个萌宠。side panel 会收起,你将看到这只宠物的详情。

左右切换

除了导航栏按钮之外,有许多 app 都支持以“滑动”的方式打开 side panel。添加一个手势识别器是很简单的。别怕,你会搞定它!

打开 ContainerViewController.swift 找到 viewDidLoad()。添加

let panGestureRecognizer = UIPanGestureRecognizer(target: self,action: #selector(handlePanGesture(_:)))
centerNavigationController.view.addGestureRecognizer(panGestureRecognizer)

这段代码声明了一个 UIPanGestureRecognizer 并指定 handlePanGesture(_:) 为它的平移手势处理器。(等会你再来实现这个方法

认,平移手势识别器会监听单指触摸,因此不需要做其它设置了。你只需要将它添加到 centerNavigationController 的 view 中就可以了。

注意:关于 iOS 中的手势识别器的更多内容,可以阅读我们的 UIGestureRecognizer Swift 教程

文件底部,UIStoryboard 扩展之上增加一个扩展,让这个类实现 UIGestureRecognizerDelegate 协议。

// MARK: Gesture recognizer

extension ContainerViewController: UIGestureRecognizerDelegate {

  @objc func handlePanGesture(_ recognizer: UIPanGestureRecognizer) {
  }
}

我说很简单吧!只剩一个步骤就完成了滑动切换面板的功能了。

让视图动起来!

当手势识别器检测到一个手势时,会调用 handlePanGesture(_:) 方法。所以本教程的最后一个任务就是实现这个方法
Now Move That View!

在上面新增加的这个方法添加代码

let gestureIsDraggingFromLeftToRight = (recognizer.veLocity(in: view).x > 0)

  switch recognizer.state {

    case .began:
      if currentState == .bothCollapsed {
        if gestureIsDraggingFromLeftToRight {
          addLeftPanelViewController()
        } else {
          addRightPanelViewController()
        }

        showShadowForCenterViewController(true)
      }

  case .changed:
    if let rview = recognizer.view {
      rview.center.x = rview.center.x + recognizer.translation(in: view).x
      recognizer.setTranslation(CGPoint.zero,in: view)
    }

  case .ended:
    if let _ = leftViewController,let rview = recognizer.view {
      // animate the side panel open or closed based on whether the view
      // has moved more or less than halfway
      let hasMovedGreaterThanHalfway = rview.center.x > view.bounds.size.width
      animateLeftPanel(shouldExpand: hasMovedGreaterThanHalfway)

    } else if let _ = rightViewController,let rview = recognizer.view {
      let hasMovedGreaterThanHalfway = rview.center.x < 0
      animateRightPanel(shouldExpand: hasMovedGreaterThanHalfway)
    }

  default:
    break
}

平移手势可以检测任意方向的滑动手势,但我们只对水平方向感兴趣。首先,用一个布尔变量 gestureIsDraggingFromLeftToRight 检查这个手势 x 方向上的速度。

我们需要监听这 3 个状态:UIGestureRecognizerState.began、UIGestureRecognizerState.changed 和UIGestureRecognizerState.ended:

  • .began: 当用户开始移动手指,同时两个面板都不可见,则根据移动的方向显示对应的面板和阴影。
  • .changed: 当用户正在平移时,让中心视图跟随用户的手指一起移动。
  • .ended: 当用户平移结束,判断左右控制器是否可见。根据是左还是右以及平移手势划过的距离,执行这个动画。

你可以在中视图上滑动,打开/隐藏左右视图,组合运用平移手势的这三种状态:位置、速度、方向。

例如,如果手势的方向是向右移动,会显示左侧面板。如果方向是向左的,显示右侧面板。

Build& run。你可以在中视图上左右滑动,打开隐藏在下面的左右面板。如果一切顺当……那就好了。

接下来做什么?

恭喜!看完本教程,你就是一个滑出式导航面板的专家了!

希望你喜欢本教程。请在这里下载完成后的项目。我肯定你会喜欢上这些猫咪和狗狗的。

如果你想尝试一些现成的库而不是自己动手,请查看 SideMenu。要深入探讨这个 UI 控件的源代码(或者来一次记忆中的旅行),请看 iOS 开发者和设计者 Ken Yarmosh文章“iOS 的新设计模式:滑出式导航”。他对这种模式的好处进行了很好的阐述,并演示了在真实环境下的常见用法

请在论坛中发表你对滑出式导航的看法。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘贴.待开发的功能:1.支持自动生成约束2.开发设置页面3.做一个浏览器插件,支持不需要下载整个工程,可即时操作当前蓝湖浏览页面4.支持Flutter语言模板生成5.支持更多平台,如Sketch等6.支持用户自定义语言模板
现实生活中,我们听到的声音都是时间连续的,我们称为这种信号叫模拟信号。模拟信号需要进行数字化以后才能在计算机中使用。目前我们在计算机上进行音频播放都需要依赖于音频文件。那么音频文件如何生成的呢?音频文件的生成过程是将声音信息采样、量化和编码产生的数字信号的过程,我们人耳所能听到的声音频率范围为(20Hz~20KHz),因此音频文件格式的最大带宽是20KHZ。根据奈奎斯特的理论,音频文件的采样率一般在40~50KHZ之间。奈奎斯特采样定律,又称香农采样定律。...............
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿遍又亿遍,久久不能离开!看着小仙紫姐姐的蹦迪视频,除了一键三连还能做什么?突发奇想,能不能把舞蹈视频转成代码舞呢?说干就干,今天就手把手教大家如何把跳舞视频转成代码舞,跟着仙女姐姐一起蹦起来~视频来源:【紫颜】见过仙女蹦迪吗 【千盏】一、核心功能设计总体来说,我们需要分为以下几步完成:从B站上把小姐姐的视频下载下来对视频进行截取GIF,把截取的GIF通过ASCII Animator进行ASCII字符转换把转换的字符gif根据每
【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至2022年4月底。我已经将这篇博客的内容写为论文,上传至arxiv:https://arxiv.org/pdf/2204.10160.pdf欢迎大家指出我论文中的问题,特别是语法与用词问题在github上,我也上传了完整的项目:https://github.com/Whiffe/Custom-ava-dataset_Custom-Spatio-Temporally-Action-Video-Dataset关于自定义ava数据集,也是后台
因为我既对接过session、cookie,也对接过JWT,今年因为工作需要也对接了gtoken的2个版本,对这方面的理解还算深入。尤其是看到官方文档评论区又小伙伴表示看不懂,所以做了这期视频内容出来:视频在这里:本期内容对应B站的开源视频因为涉及的知识点比较多,视频内容比较长。如果你觉得看视频浪费时间,可以直接阅读源码:goframe v2版本集成gtokengoframe v1版本集成gtokengoframe v2版本集成jwtgoframe v2版本session登录官方调用示例文档jwt和sess
【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)
用Android Studio的VideoView组件实现简单的本地视频播放器。本文将讲解如何使用Android视频播放器VideoView组件来播放本地视频和网络视频,实现起来还是比较简单的。VideoView组件的作用与ImageView类似,只是ImageView用于显示图片,VideoView用于播放视频。...
采用MATLAB对正弦信号,语音信号进行生成、采样和内插恢复,利用MATLAB工具箱对混杂噪声的音频信号进行滤波
随着移动互联网、云端存储等技术的快速发展,包含丰富信息的音频数据呈现几何级速率增长。这些海量数据在为人工分析带来困难的同时,也为音频认知、创新学习研究提供了数据基础。在本节中,我们通过构建生成模型来生成音频序列文件,从而进一步加深对序列数据处理问题的了解。
基于yolov5+deepsort+slowfast算法的视频实时行为检测。1. yolov5实现目标检测,确定目标坐标 2. deepsort实现目标跟踪,持续标注目标坐标 3. slowfast实现动作识别,并给出置信率 4. 用框持续框住目标,并将动作类别以及置信度显示在框上
数字电子钟设计本文主要完成数字电子钟的以下功能1、计时功能(24小时)2、秒表功能(一个按键实现开始暂停,另一个按键实现清零功能)3、闹钟功能(设置闹钟以及到时响10秒)4、校时功能5、其他功能(清零、加速、星期、八位数码管显示等)前排提示:前面几篇文章介绍过的内容就不详细介绍了,可以看我专栏的前几篇文章。PS.工程文件放在最后面总体设计本次设计主要是在前一篇文章 数字电子钟基本功能的实现 的基础上改编而成的,主要结构不变,分频器将50MHz分为较低的频率备用;dig_select
1.进入官网下载OBS stdioOpen Broadcaster Software | OBS (obsproject.com)2.下载一个插件,拓展OBS的虚拟摄像头功能链接:OBS 虚拟摄像头插件.zip_免费高速下载|百度网盘-分享无限制 (baidu.com)提取码:6656--来自百度网盘超级会员V1的分享**注意**该插件必须下载但OBS的根目录(应该是自动匹配了的)3.打开OBS,选中虚拟摄像头选择启用在底部添加一段视频录制选择下面,进行录制.
Meta公司在9月29日首次推出一款人工智能系统模型:Make-A-Video,可以从给定的文字提示生成短视频。基于**文本到图像生成技术的最新进展**,该技术旨在实现文本到视频的生成,可以仅用几个单词或几行文本生成异想天开、独一无二的视频,将无限的想象力带入生活
音频信号叠加噪声及滤波一、前言二、信号分析及加噪三、滤波去噪四、总结一、前言之前一直对硬件上的内容比较关注,但是可能是因为硬件方面的东西可能真的是比较杂,而且需要渗透的东西太多了,所以学习进展比较缓慢。因为也很少有单纯的硬件学习研究,总是会伴随着各种理论需要硬件做支撑,所以还是想要慢慢接触理论学习。但是之前总找不到切入点,不知道从哪里开始,就一直拖着。最近稍微接触了一点信号处理,就用这个当作切入点,开始接触理论学习。二、信号分析及加噪信号处理选用了matlab做工具,选了一个最简单的语音信号处理方
腾讯云 TRTC 实时音视频服务体验,从认识 TRTC 到 TRTC 的开发实践,Demo 演示& IM 服务搭建。
音乐音频分类技术能够基于音乐内容为音乐添加类别标签,在音乐资源的高效组织、检索和推荐等相关方面的研究和应用具有重要意义。传统的音乐分类方法大量使用了人工设计的声学特征,特征的设计需要音乐领域的知识,不同分类任务的特征往往并不通用。深度学习的出现给更好地解决音乐分类问题提供了新的思路,本文对基于深度学习的音乐音频分类方法进行了研究。首先将音乐的音频信号转换成声谱作为统一表示,避免了手工选取特征存在的问题,然后基于一维卷积构建了一种音乐分类模型。
C++知识精讲16 | 井字棋游戏(配资源+视频)【赋源码,双人对战】
本文主要讲解如何在Java中,使用FFmpeg进行视频的帧读取,并最终合并成Gif动态图。
在本篇博文中,我们谈及了 Swift 中 some、any 关键字以及主关联类型(primary associated types)的前世今生,并由浅及深用简明的示例向大家讲解了它们之间的奥秘玄机。