系统学习iOS动画 —— 动画组, 时间控制, 图层弹簧动画

2023-12-07 03:59

本文主要是介绍系统学习iOS动画 —— 动画组, 时间控制, 图层弹簧动画,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 动画组和时间控制

动画组可以对动画进行分组,可以向组中添加多个动画并同时调整持续时间,代理和timingFunction等属性。 对动画进行分组会产生简化的代码,并确保所有动画将作为一个实体单元同步。

这里创建一个CAAnimationGroup

    let formGroup = CAAnimationGroup()formGroup.duration = 0.5formGroup.fillMode = .backwards

然后创建一个向右移动的动画和变化透明度的动画

  let flyRight = CABasicAnimation(keyPath: "position.x")flyRight.fromValue = -view.bounds.size.width/2flyRight.toValue = view.bounds.size.width/2let fadeFieldIn = CABasicAnimation(keyPath: "opacity")fadeFieldIn.fromValue = 0.25fadeFieldIn.toValue = 1.0

为formGroup的animations赋值

    formGroup.animations = [flyRight, fadeFieldIn]

然后为控件添加上这个动画

heading.layer.add(formGroup, forKey: nil)formGroup.delegate = selfformGroup.setValue("form", forKey: "name")formGroup.setValue(username.layer, forKey: "layer")formGroup.beginTime = CACurrentMediaTime() + 0.3username.layer.add(formGroup, forKey: nil)formGroup.setValue(password.layer, forKey: "layer")formGroup.beginTime = CACurrentMediaTime() + 0.4password.layer.add(formGroup, forKey: nil)

接下来为登陆按钮添加动画组

 let groupAnimation = CAAnimationGroup()groupAnimation.beginTime = CACurrentMediaTime() + 0.5groupAnimation.duration = 0.5groupAnimation.fillMode = .backwardslet scaleDown = CABasicAnimation(keyPath: "transform.scale")scaleDown.fromValue = 3.5scaleDown.toValue = 1.0let rotate = CABasicAnimation(keyPath: "transform.rotation")rotate.fromValue = .pi / 4.0rotate.toValue = 0.0let fade = CABasicAnimation(keyPath: "opacity")fade.fromValue = 0.0fade.toValue = 1.0groupAnimation.animations = [scaleDown, rotate, fade]groupAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn)loginButton.layer.add(groupAnimation, forKey: nil)

2. 图层弹簧动画

下面解释来自于Andy_Ron

2.1 阻尼谐振子

阻尼谐振子,Damped harmonic oscillators(直译就是,逐渐衰弱的振荡器),可以理解为逐渐衰减的振动。
UIKit API简化了弹簧动画的制作,不需要了解它们的原理就可以很方便的使用。 但是,由于您现在是核心动画专家,因此您需要深入研究细节。
钟摆,理想状况下钟摆是不停的摆动,像下面的一样:
在这里插入图片描述
对应的运动轨迹图就像:
在这里插入图片描述

但现实中由于能量的损耗,钟摆的摇摆的幅度会逐渐减小:

在这里插入图片描述
对应的运动轨迹:

在这里插入图片描述
这就是一个阻尼谐振子 。
钟摆停下来所需的时间长度,以及最终振荡器图形的方式取决于振荡系统的以下参数:

  • 阻尼(damping):由于空气摩擦、机械摩擦和其他作用在系统上的外部减速力。

  • 质量(mass):摆锤越重,摆动的时间越长。

  • 刚度(stiffness):振荡器的“弹簧”越硬(钟摆的“弹簧”是指地球的引力),钟摆摆动越困难,系统停下来也越快。想象一下,如果在月球或木星上使用这个钟摆;在低重力和高重力情况下的运动将是完全不同的。

  • 初始速度(initial velocity):推一下钟摆。

2.2 视图弹簧动画 vs 图层弹簧动画

UIKit以动态方式调整所有其他变量,使系统在给定的持续时间内稳定下来。 这就是为什么UIKit弹簧动画有时有点被迫 停下来的感觉。 如果仔细观察会发现UIKit动画有点不太自然。
幸运的是,核心允许通过CASpringAnimation类为图层属性创建合适的弹簧动画。 CASpringAnimation在幕后为UIKit创建弹簧动画,但是当我们直接调用它时,可以设置系统的各种变量,让动画自己稳定下来。 这种方法的缺点是不能设置固定的持续时间(duration);持续时间取决于提供的其它变量,然后系统计算所得。

CASpringAnimation的一些属性(对应之前振荡系统的参数):

  • damping 阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快
  • mass 质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大
  • stiffness 刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快
  • initialVelocity 初始速率,动画视图的初始速度大小。速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反

2.3 图层弹簧动画应用

将之前在animationDidStop的动画

  let pulse = CABasicAnimation(keyPath: "transform.scale")pulse.fromValue = 1.25pulse.toValue = 1.0pulse.duration = 0.25layer?.add(pulse, forKey: nil)

修改为

     let pulse = CASpringAnimation(keyPath: "transform.scale")pulse.damping = 7.5pulse.fromValue = 1.25pulse.toValue = 1.0pulse.duration = pulse.settlingDurationlayer?.add(pulse, forKey: nil)

运行后发现动画明显自然很多
继续将其他的动画也修改好:
将tintBackgroundColor里面的动画改为:

func tintBackgroundColor(layer: CALayer, toColor: UIColor) {let tint = CASpringAnimation(keyPath: "backgroundColor")tint.damping = 5.0tint.initialVelocity = -10.0tint.fromValue = layer.backgroundColortint.toValue = toColor.cgColortint.duration = tint.settlingDurationlayer.add(tint, forKey: nil)layer.backgroundColor = toColor.cgColor
}

将roundCorners里面的动画改为:

func roundCorners(layer: CALayer, toRadius: CGFloat) {let round = CASpringAnimation(keyPath: "cornerRadius")round.damping = 5.0round.fromValue = layer.cornerRadiusround.toValue = toRadiusround.duration = round.settlingDurationlayer.add(round, forKey: nil)layer.cornerRadius = toRadius
}

在textFieldDidEndEditing里面添加判断,如果输入小于5,那么就添加动画。

 func textFieldDidEndEditing(_ textField: UITextField) {guard let text = textField.text else { return }if text.count < 5 {// add animations herelet jump = CASpringAnimation(keyPath: "position.y")jump.initialVelocity = 100.0jump.mass = 10.0jump.stiffness = 1500.0jump.damping = 50.0jump.fromValue = textField.layer.position.y + 1.0jump.toValue = textField.layer.position.yjump.duration = jump.settlingDurationtextField.layer.add(jump, forKey: nil)textField.layer.borderWidth = 3.0textField.layer.borderColor = UIColor.clear.cgColorlet flash = CASpringAnimation(keyPath: "borderColor")flash.damping = 7.0flash.stiffness = 200.0flash.fromValue = UIColor(red: 1.0, green: 0.27, blue: 0.0, alpha: 1.0).cgColorflash.toValue = UIColor.white.cgColorflash.duration = flash.settlingDurationtextField.layer.add(flash, forKey: nil)textField.layer.cornerRadius = 5}}

2.4 弹簧动画属性

CASpringAnimation预定义的弹簧动画属性的默认值分别是:

damping: 10.0
mass: 1.0
stiffness: 100.0
initialVelocity: 0.0
  • initialVelocity: 附着在弹簧上的物体的初始速度。默认为零,表示一个不动的对象。负值表示对象远离弹簧附着点,正值表示对象向弹簧附着点移动。
  • mass:附着在弹簧末端的物体的质量。必须大于0。默认为1。数值越大,对象跳跃的更高,并且稳定下来的时间更久了。
  • stiffness : 弹簧刚度系数。必须大于0。默认为100。让跳跃高度降低。
  • damping: 阻尼系数。必须大于或等于0,默认为10。增加阻尼系数可以让动画更快地稳定下来。

完整代码:

//
//  ViewController.swift
//  AirLoginAnimation
//
//  Created by aibus on 2021/10/27.
//import UIKitclass ViewController: UIViewController {let screenWidth = UIScreen.main.bounds.size.widthlet screenHeight = UIScreen.main.bounds.size.heightlet titleLabel = UILabel()let backgroundImage = UIImageView()let usernameTextField = TextField()let passwordTextField = TextField()let loginButton = UIButton()let cloud1 = UIImageView()let cloud2 = UIImageView()let cloud3 = UIImageView()let cloud4 = UIImageView()let spinner = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.large)let status = UIImageView(image: UIImage(named: "banner"))let label = UILabel()let info = UILabel()let messages = ["Connecting ...", "Authorizing ...", "Sending credentials ...", "Failed"]var statusPosition = CGPoint.zerooverride func viewDidLoad() {super.viewDidLoad()// Do any additional setup after loading the view.view.addSubview(backgroundImage)view.addSubview(titleLabel)view.addSubview(usernameTextField)view.addSubview(passwordTextField)view.addSubview(loginButton)view.addSubview(cloud1)view.addSubview(cloud2)view.addSubview(cloud3)view.addSubview(cloud4)loginButton.addSubview(spinner)let textFieldWidth = screenWidth - 60let buttonWidth = 260backgroundImage.image = UIImage(named: "bg-sunny")backgroundImage.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)titleLabel.text = "Bahama Login"titleLabel.textColor = .whitetitleLabel.font = UIFont.systemFont(ofSize: 28)let titleWidth = titleLabel.intrinsicContentSize.widthtitleLabel.frame = CGRect(x: (screenWidth - titleWidth) / 2 , y: 120, width: titleWidth, height: titleLabel.intrinsicContentSize.height)usernameTextField.backgroundColor = .whiteusernameTextField.layer.cornerRadius = 5usernameTextField.placeholder = "  Username"usernameTextField.delegate = selfusernameTextField.frame = CGRect(x: 30, y: 202, width: textFieldWidth, height: 40)passwordTextField.backgroundColor = .whitepasswordTextField.layer.cornerRadius = 5passwordTextField.placeholder = "  Password"passwordTextField.delegate = selfpasswordTextField.frame = CGRect(x: 30, y: 263, width: textFieldWidth, height: 40)loginButton.frame = CGRect(x: (Int(screenWidth) - buttonWidth) / 2, y: 343, width: buttonWidth, height: 50)loginButton.setTitle("Login", for: .normal)loginButton.setTitleColor(.red, for: .normal)loginButton.layer.cornerRadius = 5loginButton.backgroundColor = UIColor(red: 0.63, green: 0.84, blue: 0.35, alpha: 1.0)loginButton.addTarget(self, action: #selector(handleLogin), for: .touchUpInside)spinner.frame = CGRect(x: -20.0, y: 6.0, width: 20.0, height: 20.0)spinner.startAnimating()spinner.alpha = 0.0cloud1.frame = CGRect(x: -120, y: 79, width: 160, height: 50)cloud1.image = UIImage(named: "bg-sunny-cloud-1")cloud2.frame = CGRect(x: 256, y: 213, width: 160, height: 50)cloud2.image = UIImage(named: "bg-sunny-cloud-2")cloud3.frame = CGRect(x: 284, y: 503, width: 74, height: 35)cloud3.image = UIImage(named: "bg-sunny-cloud-3")cloud4.frame = CGRect(x:22 , y: 545, width: 115, height: 50)cloud4.image = UIImage(named: "bg-sunny-cloud-4")status.isHidden = truestatus.center = loginButton.centerview.addSubview(status)label.frame = CGRect(x: 0.0, y: 0.0, width: status.frame.size.width, height: status.frame.size.height)label.font = UIFont(name: "HelveticaNeue", size: 18.0)label.textColor = UIColor(red: 0.89, green: 0.38, blue: 0.0, alpha: 1.0)label.textAlignment = .centerstatus.addSubview(label)statusPosition = status.centerinfo.frame = CGRect(x: 0.0, y: loginButton.center.y + 60.0,  width: view.frame.size.width, height: 30)info.backgroundColor = UIColor.clearinfo.font = UIFont(name: "HelveticaNeue", size: 12.0)info.textAlignment = .centerinfo.textColor = UIColor.whiteinfo.text = "Tap on a field and enter username and password"view.insertSubview(info, belowSubview: loginButton)}override func viewWillAppear(_ animated: Bool) {super.viewWillAppear(animated)let formGroup = CAAnimationGroup()formGroup.duration = 0.5formGroup.fillMode = .backwardslet flyRight = CABasicAnimation(keyPath: "position.x")flyRight.fromValue = -view.bounds.size.width/2flyRight.toValue = view.bounds.size.width/2let fadeFieldIn = CABasicAnimation(keyPath: "opacity")fadeFieldIn.fromValue = 0.25fadeFieldIn.toValue = 1.0formGroup.animations = [flyRight, fadeFieldIn]titleLabel.layer.add(formGroup, forKey: nil)formGroup.delegate = selfformGroup.setValue("form", forKey: "name")formGroup.setValue(usernameTextField.layer, forKey: "layer")formGroup.beginTime = CACurrentMediaTime() + 0.3usernameTextField.layer.add(formGroup, forKey: nil)formGroup.setValue(passwordTextField.layer, forKey: "layer")formGroup.beginTime = CACurrentMediaTime() + 0.4passwordTextField.layer.add(formGroup, forKey: nil)}override func viewDidAppear(_ animated: Bool) {super.viewDidAppear(animated)let fadeIn = CABasicAnimation(keyPath: "opacity")fadeIn.fromValue = 0.0fadeIn.toValue = 1.0fadeIn.duration = 0.5fadeIn.fillMode = .backwardsfadeIn.beginTime = CACurrentMediaTime() + 0.5cloud1.layer.add(fadeIn, forKey: nil)fadeIn.beginTime = CACurrentMediaTime() + 0.7cloud2.layer.add(fadeIn, forKey: nil)fadeIn.beginTime = CACurrentMediaTime() + 0.9cloud3.layer.add(fadeIn, forKey: nil)fadeIn.beginTime = CACurrentMediaTime() + 1.1cloud4.layer.add(fadeIn, forKey: nil)let groupAnimation = CAAnimationGroup()groupAnimation.beginTime = CACurrentMediaTime() + 0.5groupAnimation.duration = 0.5groupAnimation.fillMode = .backwardslet scaleDown = CABasicAnimation(keyPath: "transform.scale")scaleDown.fromValue = 3.5scaleDown.toValue = 1.0let rotate = CABasicAnimation(keyPath: "transform.rotation")rotate.fromValue = .pi / 4.0rotate.toValue = 0.0let fade = CABasicAnimation(keyPath: "opacity")fade.fromValue = 0.0fade.toValue = 1.0groupAnimation.animations = [scaleDown, rotate, fade]groupAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn)loginButton.layer.add(groupAnimation, forKey: nil)animateCloud(layer: cloud1.layer)animateCloud(layer: cloud2.layer)animateCloud(layer: cloud3.layer)animateCloud(layer: cloud4.layer)let flyLeft = CABasicAnimation(keyPath: "position.x")flyLeft.fromValue = info.layer.position.x + view.frame.size.widthflyLeft.toValue = info.layer.position.xflyLeft.duration = 5.0info.layer.add(flyLeft, forKey: "infoappear")let fadeLabelIn = CABasicAnimation(keyPath: "opacity")fadeLabelIn.fromValue = 0.2fadeLabelIn.toValue = 1.0fadeLabelIn.duration = 4.5info.layer.add(fadeLabelIn, forKey: "fadein")}@objc func handleLogin() {view.endEditing(true)UIView.animate(withDuration: 1.5, delay: 0.0, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.0, options: [], animations: {self.loginButton.bounds.size.width += 80.0}, completion: nil)UIView.animate(withDuration: 0.33, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.0, options: [], animations: {self.loginButton.center.y += 60.0self.spinner.center = CGPoint(x: 40.0,y: self.loginButton.frame.size.height/2)self.spinner.alpha = 1.0}, completion: { _ inself.showMessage(index:0)})let tintColor = UIColor(red: 0.85, green: 0.83, blue: 0.45, alpha: 1.0)tintBackgroundColor(layer: loginButton.layer, toColor: tintColor)roundCorners(layer: loginButton.layer, toRadius: 25.0)}func showMessage(index: Int) {label.text = messages[index]UIView.transition(with: status, duration: 0.33, options: [.curveEaseOut, .transitionFlipFromTop], animations: {self.status.isHidden = false}, completion: { _ in//transition completiondelay(2.0) {if index < self.messages.count-1 {self.removeMessage(index: index)} else {self.resetForm()}}})}func removeMessage(index: Int) {UIView.animate(withDuration: 0.33, delay: 0.0, options: [], animations: {self.status.center.x += self.view.frame.size.width}, completion: { _ inself.status.isHidden = trueself.status.center = self.statusPositionself.showMessage(index: index+1)})}func resetForm() {UIView.transition(with: status, duration: 0.2, options: .transitionFlipFromTop, animations: {self.status.isHidden = trueself.status.center = self.statusPosition}, completion: { _ inlet tintColor = UIColor(red: 0.63, green: 0.84, blue: 0.35, alpha: 1.0)tintBackgroundColor(layer: self.loginButton.layer, toColor: tintColor)roundCorners(layer: self.loginButton.layer, toRadius: 10.0)})UIView.animate(withDuration: 0.2, delay: 0.0, options: [], animations: {self.spinner.center = CGPoint(x: -20.0, y: 16.0)self.spinner.alpha = 0.0self.loginButton.bounds.size.width -= 80.0self.loginButton.center.y -= 60.0}, completion: nil)}func animateCloud(layer: CALayer) {//1let cloudSpeed = 60.0 / Double(view.layer.frame.size.width)let duration: TimeInterval = Double(view.layer.frame.size.width - layer.frame.origin.x) * cloudSpeed//2let cloudMove = CABasicAnimation(keyPath: "position.x")cloudMove.duration = durationcloudMove.toValue = self.view.bounds.size.width + layer.bounds.width/2cloudMove.delegate = selfcloudMove.fillMode = .forwardscloudMove.setValue("cloud", forKey: "name")cloudMove.setValue(layer, forKey: "layer")layer.add(cloudMove, forKey: nil)}}func delay(_ seconds: Double, completion: @escaping ()->Void) {DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: completion)
}func tintBackgroundColor(layer: CALayer, toColor: UIColor) {let tint = CASpringAnimation(keyPath: "backgroundColor")tint.damping = 5.0tint.initialVelocity = -10.0tint.fromValue = layer.backgroundColortint.toValue = toColor.cgColortint.duration = tint.settlingDurationlayer.add(tint, forKey: nil)layer.backgroundColor = toColor.cgColor
}func roundCorners(layer: CALayer, toRadius: CGFloat) {let round = CASpringAnimation(keyPath: "cornerRadius")round.damping = 5.0round.fromValue = layer.cornerRadiusround.toValue = toRadiusround.duration = round.settlingDurationlayer.add(round, forKey: nil)layer.cornerRadius = toRadius
}class TextField: UITextField {let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)override open func textRect(forBounds bounds: CGRect) -> CGRect {return bounds.inset(by: padding)}override open func placeholderRect(forBounds bounds: CGRect) -> CGRect {return bounds.inset(by: padding)}override open func editingRect(forBounds bounds: CGRect) -> CGRect {return bounds.inset(by: padding)}
}extension ViewController: CAAnimationDelegate {func animationDidStop(_ anim: CAAnimation,finished flag: Bool) {print("animation did finish")guard let name = anim.value(forKey: "name") as? String else {return}if name == "form" {//form field foundlet layer = anim.value(forKey: "layer") as? CALayeranim.setValue(nil, forKey: "layer")let pulse = CASpringAnimation(keyPath: "transform.scale")pulse.damping = 7.5pulse.fromValue = 1.25pulse.toValue = 1.0pulse.duration = pulse.settlingDurationlayer?.add(pulse, forKey: nil)}if name == "cloud" {if let layer = anim.value(forKey: "layer") as? CALayer {anim.setValue(nil, forKey: "layer")layer.position.x = -layer.bounds.width/2delay(0.5) {self.animateCloud(layer: layer)}}}}
}
extension ViewController: UITextFieldDelegate {func textFieldDidBeginEditing(_ textField: UITextField) {guard let runningAnimations = info.layer.animationKeys() else {return}print(runningAnimations)info.layer.removeAnimation(forKey: "infoappear")info.layer.removeAnimation(forKey: "fadein")}func textFieldDidEndEditing(_ textField: UITextField) {guard let text = textField.text else { return }if text.count < 5 {// add animations herelet jump = CASpringAnimation(keyPath: "position.y")jump.initialVelocity = 100.0jump.mass = 10.0jump.stiffness = 1500.0jump.damping = 50.0jump.fromValue = textField.layer.position.y + 1.0jump.toValue = textField.layer.position.yjump.duration = jump.settlingDurationtextField.layer.add(jump, forKey: nil)textField.layer.borderWidth = 3.0textField.layer.borderColor = UIColor.clear.cgColorlet flash = CASpringAnimation(keyPath: "borderColor")flash.damping = 7.0flash.stiffness = 200.0flash.fromValue = UIColor(red: 1.0, green: 0.27, blue: 0.0, alpha: 1.0).cgColorflash.toValue = UIColor.white.cgColorflash.duration = flash.settlingDurationtextField.layer.add(flash, forKey: nil)textField.layer.cornerRadius = 5}}
}

这篇关于系统学习iOS动画 —— 动画组, 时间控制, 图层弹簧动画的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/464408

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设