在AIGC类的APP中,实现那种一个字一个字、一行一行地打印出文字的效果,可以通过多种方法来实现。下面是一些实现方法,使用Swift和OC来举例说明。
OC版
1. 基于定时器的逐字打印效果
可以使用NSTimer来逐字逐行地显示文字。
#import "ViewController.h" @interface ViewController () @property (nonatomic, strong) UITextView *textView; @property (nonatomic, strong) NSString *content; @property (nonatomic, assign) NSInteger currentIndex; @property (nonatomic, strong) NSTimer *timer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.textView = [[UITextView alloc] initWithFrame:self.view.bounds]; self.textView.font = [UIFont systemFontOfSize:18]; self.textView.editable = NO; self.textView.scrollEnabled = YES; [self.view addSubview:self.textView]; self.content = @"这是需要逐字逐行打印的文字内容。n让我们来实现它。"; self.currentIndex = 0; [self startPrinting]; } - (void)startPrinting { self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(printNextCharacter) userInfo:nil repeats:YES]; } - (void)printNextCharacter { if (self.currentIndex >= self.content.length) { [self.timer invalidate]; self.timer = nil; return; } NSRange range = NSMakeRange(self.currentIndex, 1); NSString *nextCharacter = [self.content substringWithRange:range]; self.textView.text = [self.textView.text stringByAppendingString:nextCharacter]; self.currentIndex += 1; } @end
2. 使用CADisplayLink来实现高精度逐字打印
CADisplayLink可以在屏幕刷新时调用指定的方法,相较于NSTimer,其精度和性能更高。
#import "ViewController.h" @interface ViewController () @property (nonatomic, strong) UITextView *textView; @property (nonatomic, strong) NSString *content; @property (nonatomic, assign) NSInteger currentIndex; @property (nonatomic, strong) CADisplayLink *displayLink; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.textView = [[UITextView alloc] initWithFrame:self.view.bounds]; self.textView.font = [UIFont systemFontOfSize:18]; self.textView.editable = NO; self.textView.scrollEnabled = YES; [self.view addSubview:self.textView]; self.content = @"这是需要逐字逐行打印的文字内容。n让我们来实现它。"; self.currentIndex = 0; [self startPrinting]; } - (void)startPrinting { self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(printNextCharacter)]; self.displayLink.preferredFramesPerSecond = 10; // 控制打印速度 [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; } - (void)printNextCharacter { if (self.currentIndex >= self.content.length) { [self.displayLink invalidate]; self.displayLink = nil; return; } NSRange range = NSMakeRange(self.currentIndex, 1); NSString *nextCharacter = [self.content substringWithRange:range]; self.textView.text = [self.textView.text stringByAppendingString:nextCharacter]; self.currentIndex += 1; } @end
3. CATextLayer + Animation
还可以使用CATextLayer和动画来实现更为复杂和流畅的逐字逐行打印效果。
#import "ViewController.h" #import <QuartzCore/QuartzCore.h> @interface ViewController () @property (nonatomic, strong) CATextLayer *textLayer; @property (nonatomic, strong) NSString *content; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.textLayer = [CATextLayer layer]; self.textLayer.frame = self.view.bounds; self.textLayer.fontSize = 18; self.textLayer.alignmentMode = kCAAlignmentLeft; self.textLayer.contentsScale = [UIScreen mainScreen].scale; self.textLayer.wrapped = YES; [self.view.layer addSublayer:self.textLayer]; self.content = @"这是需要逐字逐行打印的文字内容。n让我们来实现它。"; [self startPrinting]; } - (void)startPrinting { self.textLayer.string = @""; for (NSInteger index = 0; index < self.content.length; index++) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(index * 0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSString *nextCharacter = [self.content substringWithRange:NSMakeRange(index, 1)]; self.textLayer.string = [self.textLayer.string stringByAppendingString:nextCharacter]; }); } } @end
Swift版
1. 基于定时器的逐字打印效果
可以使用Timer来逐字逐行地显示文字。
import UIKit class ViewController: UIViewController { private let textView = UITextView() private let content = "这是需要逐字逐行打印的文字内容。n让我们来实现它。" private var currentIndex = 0 private var timer: Timer? override func viewDidLoad() { super.viewDidLoad() view.addSubview(textView) textView.frame = view.bounds textView.font = UIFont.systemFont(ofSize: 18) textView.isEditable = false textView.isScrollEnabled = true startPrinting() } private func startPrinting() { timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(printNextCharacter), userInfo: nil, repeats: true) } @objc private func printNextCharacter() { guard currentIndex < content.count else { timer?.invalidate() timer = nil return } let nextIndex = content.index(content.startIndex, offsetBy: currentIndex) textView.text.append(content[nextIndex]) currentIndex += 1 } }
2. 使用CADisplayLink来实现高精度逐字打印
CADisplayLink可以在屏幕刷新时调用指定的方法,相较于Timer,其精度和性能更高。
import UIKit class ViewController: UIViewController { private let textView = UITextView() private let content = "这是需要逐字逐行打印的文字内容。n让我们来实现它。" private var currentIndex = 0 private var displayLink: CADisplayLink? override func viewDidLoad() { super.viewDidLoad() view.addSubview(textView) textView.frame = view.bounds textView.font = UIFont.systemFont(ofSize: 18) textView.isEditable = false textView.isScrollEnabled = true startPrinting() } private func startPrinting() { displayLink = CADisplayLink(target: self, selector: #selector(printNextCharacter)) displayLink?.preferredFramesPerSecond = 10 // 控制打印速度 displayLink?.add(to: .main, forMode: .default) } @objc private func printNextCharacter() { guard currentIndex < content.count else { displayLink?.invalidate() displayLink = nil return } let nextIndex = content.index(content.startIndex, offsetBy: currentIndex) textView.text.append(content[nextIndex]) currentIndex += 1 } }
3. CATextLayer + Animation
还可以使用CATextLayer和动画来实现更为复杂和流畅的逐字逐行打印效果。
import UIKit class ViewController: UIViewController { private let textLayer = CATextLayer() private let content = "这是需要逐字逐行打印的文字内容。n让我们来实现它。" override func viewDidLoad() { super.viewDidLoad() textLayer.frame = view.bounds textLayer.fontSize = 18 textLayer.alignmentMode = .left textLayer.contentsScale = UIScreen.main.scale textLayer.isWrapped = true view.layer.addSublayer(textLayer) startPrinting() } private func startPrinting() { textLayer.string = "" for (index, character) in content.enumerated() { DispatchQueue.main.asyncAfter(deadline: .now() + Double(index) * 0.1) { self.textLayer.string = "(self.textLayer.string ?? "")(character)" } } } }