系统学习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

相关文章

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

go中的时间处理过程

《go中的时间处理过程》:本文主要介绍go中的时间处理过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 获取当前时间2 获取当前时间戳3 获取当前时间的字符串格式4 相互转化4.1 时间戳转时间字符串 (int64 > string)4.2 时间字符串转时间

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

Spring如何使用注解@DependsOn控制Bean加载顺序

《Spring如何使用注解@DependsOn控制Bean加载顺序》:本文主要介绍Spring如何使用注解@DependsOn控制Bean加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录1.javascript 前言2. 代码实现总结1. 前言默认情况下,Spring加载Bean的顺

linux重启命令有哪些? 7个实用的Linux系统重启命令汇总

《linux重启命令有哪些?7个实用的Linux系统重启命令汇总》Linux系统提供了多种重启命令,常用的包括shutdown-r、reboot、init6等,不同命令适用于不同场景,本文将详细... 在管理和维护 linux 服务器时,完成系统更新、故障排查或日常维护后,重启系统往往是必不可少的步骤。本文

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间

Mac系统下卸载JAVA和JDK的步骤

《Mac系统下卸载JAVA和JDK的步骤》JDK是Java语言的软件开发工具包,它提供了开发和运行Java应用程序所需的工具、库和资源,:本文主要介绍Mac系统下卸载JAVA和JDK的相关资料,需... 目录1. 卸载系统自带的 Java 版本检查当前 Java 版本通过命令卸载系统 Java2. 卸载自定

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五