屬性動畫(顯示動)

来源:http://www.cnblogs.com/EchoHG/archive/2017/10/04/7625750.html
-Advertisement-
Play Games

屬性動畫 CAAnimationDelegate在任何頭文件中都找不到,但是可以在CAAnimation頭文件或者蘋果開發者文檔中找到相關函數。在這個例子中,我們用-animationDidStop:finished:方法在動畫結束之後來更新圖層的backgroundColor。 當更新屬性的時候, ...


屬性動畫

CAAnimationDelegate在任何頭文件中都找不到,但是可以在CAAnimation頭文件或者蘋果開發者文檔中找到相關函數。在這個例子中,我們用-animationDidStop:finished:方法在動畫結束之後來更新圖層的backgroundColor

當更新屬性的時候,我們需要設置一個新的事務,並且禁用圖層行為。否則動畫會發生兩次,一個是因為顯式的CABasicAnimation,另一次是因為隱式動畫,具體實現見訂單8.3。

清單8.3 動畫完成之後修改圖層的背景色

 1 @implementation ViewController
 2 
 3 - (void)viewDidLoad
 4 {
 5     [super viewDidLoad];
 6     //create sublayer
 7     self.colorLayer = [CALayer layer];
 8     self.colorLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
 9     self.colorLayer.backgroundColor = [UIColor blueColor].CGColor;
10     //add it to our view
11     [self.layerView.layer addSublayer:self.colorLayer];
12 }
13 
14 - (IBAction)changeColor
15 {
16     //create a new random color
17     CGFloat red = arc4random() / (CGFloat)INT_MAX;
18     CGFloat green = arc4random() / (CGFloat)INT_MAX;
19     CGFloat blue = arc4random() / (CGFloat)INT_MAX;
20     UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
21     //create a basic animation
22     CABasicAnimation *animation = [CABasicAnimation animation];
23     animation.keyPath = @"backgroundColor";
24     animation.toValue = (__bridge id)color.CGColor;
25     animation.delegate = self;
26     //apply animation to layer
27     [self.colorLayer addAnimation:animation forKey:nil];
28 }
29 
30 - (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag
31 {
32     //set the backgroundColor property to match animation toValue
33     [CATransaction begin];
34     [CATransaction setDisableActions:YES];
35     self.colorLayer.backgroundColor = (__bridge CGColorRef)anim.toValue;
36     [CATransaction commit];
37 }
38 
39 @end
View Code

 

CAAnimation而言,使用委托模式而不是一個完成塊會帶來一個問題,就是當你有多個動畫的時候,無法在在回調方法中區分。在一個視圖控制器中創建動畫的時候,通常會用控制器本身作為一個委托(如清單8.3所示),但是所有的動畫都會調用同一個回調方法,所以你就需要判斷到底是那個圖層的調用。

考慮一下第三章的鬧鐘,“圖層幾何學”,我們通過簡單地每秒更新指針的角度來實現一個鐘,但如果指針動態地轉向新的位置會更加真實。

我們不能通過隱式動畫來實現因為這些指針都是UIView的實例,所以圖層的隱式動畫都被禁用了。我們可以簡單地通過UIView的動畫方法來實現。但如果想更好地控制動畫時間,使用顯式動畫會更好(更多內容見第十章)。使用CABasicAnimation來做動畫可能會更加複雜,因為我們需要在-animationDidStop:finished:中檢測指針狀態(用於設置結束的位置)。

動畫本身會作為一個參數傳入委托的方法,也許你會認為可以控制器中把動畫存儲為一個屬性,然後在回調用比較,但實際上並不起作用,因為委托傳入的動畫參數是原始值的一個深拷貝,從而不是同一個值。

當使用-addAnimation:forKey:把動畫添加到圖層,這裡有一個到目前為止我們都設置為nilkey參數。這裡的鍵是-animationForKey:方法找到對應動畫的唯一標識符,而當前動畫的所有鍵都可以用animationKeys獲取。如果我們對每個動畫都關聯一個唯一的鍵,就可以對每個圖層迴圈所有鍵,然後調用-animationForKey:來比對結果。儘管這不是一個優雅的實現。

幸運的是,還有一種更加簡單的方法。像所有的NSObject子類一樣,CAAnimation實現了KVC(鍵-值-編碼)協議,於是你可以用-setValue:forKey:-valueForKey:方法來存取屬性。但是CAAnimation有一個不同的性能:它更像一個NSDictionary,可以讓你隨意設置鍵值對,即使和你使用的動畫類所聲明的屬性並不匹配。

這意味著你可以對動畫用任意類型打標簽。在這裡,我們給UIView類型的指針添加的動畫,所以可以簡單地判斷動畫到底屬於哪個視圖,然後在委托方法中用這個信息正確地更新鐘的指針(清單8.4)。

清單8.4 使用KVC對動畫打標簽

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIImageView *hourHand;
 4 @property (nonatomic, weak) IBOutlet UIImageView *minuteHand;
 5 @property (nonatomic, weak) IBOutlet UIImageView *secondHand;
 6 @property (nonatomic, weak) NSTimer *timer;
 7 
 8 @end
 9 
10 @implementation ViewController
11 
12 - (void)viewDidLoad
13 {
14     [super viewDidLoad];
15     //adjust anchor points
16     self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
17     self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
18     self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
19     //start timer
20     self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tick) userInfo:nil repeats:YES];
21     //set initial hand positions
22     [self updateHandsAnimated:NO];
23 }
24 
25 - (void)tick
26 {
27     [self updateHandsAnimated:YES];
28 }
29 
30 - (void)updateHandsAnimated:(BOOL)animated
31 {
32     //convert time to hours, minutes and seconds
33     NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
34     NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
35     NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
36     CGFloat hourAngle = (components.hour / 12.0) * M_PI * 2.0;
37     //calculate hour hand angle //calculate minute hand angle
38     CGFloat minuteAngle = (components.minute / 60.0) * M_PI * 2.0;
39     //calculate second hand angle
40     CGFloat secondAngle = (components.second / 60.0) * M_PI * 2.0;
41     //rotate hands
42     [self setAngle:hourAngle forHand:self.hourHand animated:animated];
43     [self setAngle:minuteAngle forHand:self.minuteHand animated:animated];
44     [self setAngle:secondAngle forHand:self.secondHand animated:animated];
45 }
46 
47 - (void)setAngle:(CGFloat)angle forHand:(UIView *)handView animated:(BOOL)animated
48 {
49     //generate transform
50     CATransform3D transform = CATransform3DMakeRotation(angle, 0, 0, 1);
51     if (animated) {
52         //create transform animation
53         CABasicAnimation *animation = [CABasicAnimation animation];
54         [self updateHandsAnimated:NO];
55         animation.keyPath = @"transform";
56         animation.toValue = [NSValue valueWithCATransform3D:transform];
57         animation.duration = 0.5;
58         animation.delegate = self;
59         [animation setValue:handView forKey:@"handView"];
60         [handView.layer addAnimation:animation forKey:nil];
61     } else {
62         //set transform directly
63         handView.layer.transform = transform;
64     }
65 }
66 
67 - (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag
68 {
69     //set final position for hand view
70     UIView *handView = [anim valueForKey:@"handView"];
71     handView.layer.transform = [anim.toValue CATransform3DValue];
72 }
View Code

 

我們成功的識別出每個圖層停止動畫的時間,然後更新它的變換到一個新值,很好。

不幸的是,即使做了這些,還是有個問題,清單8.4在模擬器上運行的很好,但當真正跑在iOS設備上時,我們發現在-animationDidStop:finished:委托方法調用之前,指針會迅速返回到原始值,這個清單8.3圖層顏色發生的情況一樣。

問題在於回調方法在動畫完成之前已經被調用了,但不能保證這發生在屬性動畫返回初始狀態之前。這同時也很好地說明瞭為什麼要在真實的設備上測試動畫代碼,而不僅僅是模擬器。

我們可以用一個fillMode屬性來解決這個問題,下一章會詳細說明,這裡知道在動畫之前設置它比在動畫結束之後更新屬性更加方便。

關鍵幀動畫

CABasicAnimation揭示了大多數隱式動畫背後依賴的機制,這的確很有趣,但是顯式地給圖層添加CABasicAnimation相較於隱式動畫而言,只能說費力不討好。

CAKeyframeAnimation是另一種UIKit沒有暴露出來但功能強大的類。和CABasicAnimation類似,CAKeyframeAnimation同樣是CAPropertyAnimation的一個子類,它依然作用於單一的一個屬性,但是和CABasicAnimation不一樣的是,它不限制於設置一個起始和結束的值,而是可以根據一連串隨意的值來做動畫。

關鍵幀起源於傳動動畫,意思是指主導的動畫在顯著改變發生時重繪當前幀(也就是關鍵幀),每幀之間剩下的繪製(可以通過關鍵幀推算出)將由熟練的藝術家來完成。CAKeyframeAnimation也是同樣的道理:你提供了顯著的幀,然後Core Animation在每幀之間進行插入。

我們可以用之前使用顏色圖層的例子來演示,設置一個顏色的數組,然後通過關鍵幀動畫播放出來(清單8.5)

清單8.5 使用CAKeyframeAnimation應用一系列顏色的變化

 1 - (IBAction)changeColor
 2 {
 3     //create a keyframe animation
 4     CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
 5     animation.keyPath = @"backgroundColor";
 6     animation.duration = 2.0;
 7     animation.values = @[
 8                          (__bridge id)[UIColor blueColor].CGColor,
 9                          (__bridge id)[UIColor redColor].CGColor,
10                          (__bridge id)[UIColor greenColor].CGColor,
11                          (__bridge id)[UIColor blueColor].CGColor ];
12     //apply animation to layer
13     [self.colorLayer addAnimation:animation forKey:nil];
14 }
View Code

 

註意到序列中開始和結束的顏色都是藍色,這是因為CAKeyframeAnimation並不能自動把當前值作為第一幀(就像CABasicAnimation那樣把fromValue設為nil)。動畫會在開始的時候突然跳轉到第一幀的值,然後在動畫結束的時候突然恢復到原始的值。所以為了動畫的平滑特性,我們需要開始和結束的關鍵幀來匹配當前屬性的值。

當然可以創建一個結束和開始值不同的動畫,那樣的話就需要在動畫啟動之前手動更新屬性和最後一幀的值保持一致,就和之前討論的一樣。

我們用duration屬性把動畫時間從預設的0.25秒增加到2秒,以便於動畫做的不那麼快。運行它,你會發現動畫通過顏色不斷迴圈,但效果看起來有些奇怪。原因在於動畫以一個恆定的步調在運行。當在每個動畫之間過渡的時候並沒有減速,這就產生了一個略微奇怪的效果,為了讓動畫看起來更自然,我們需要調整一下緩衝,第十章將會詳細說明。

提供一個數組的值就可以按照顏色變化做動畫,但一般來說用數組來描述動畫運動並不直觀。CAKeyframeAnimation有另一種方式去指定動畫,就是使用CGPathpath屬性可以用一種直觀的方式,使用Core Graphics函數定義運動序列來繪製動畫。

我們來用一個宇宙飛船沿著一個簡單曲線的實例演示一下。為了創建路徑,我們需要使用一個三次貝塞爾曲線,它是一種使用開始點,結束點和另外兩個控制點來定義形狀的曲線,可以通過使用一個基於C的Core Graphics繪圖指令來創建,不過用UIKit提供的UIBezierPath類會更簡單。

我們這次用CAShapeLayer來在屏幕上繪製曲線,儘管對動畫來說並不是必須的,但這會讓我們的動畫更加形象。繪製完CGPath之後,我們用它來創建一個CAKeyframeAnimation,然後用它來應用到我們的宇宙飛船。代碼見清單8.6,結果見圖8.1。

清單8.6 沿著一個貝塞爾曲線對圖層做動畫

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *containerView;
 4 
 5 @end
 6 
 7 @implementation ViewController
 8 
 9 - (void)viewDidLoad
10 {
11     [super viewDidLoad];
12     //create a path
13     UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
14     [bezierPath moveToPoint:CGPointMake(0, 150)];
15     [bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
16     //draw the path using a CAShapeLayer
17     CAShapeLayer *pathLayer = [CAShapeLayer layer];
18     pathLayer.path = bezierPath.CGPath;
19     pathLayer.fillColor = [UIColor clearColor].CGColor;
20     pathLayer.strokeColor = [UIColor redColor].CGColor;
21     pathLayer.lineWidth = 3.0f;
22     [self.containerView.layer addSublayer:pathLayer];
23     //add the ship
24     CALayer *shipLayer = [CALayer layer];
25     shipLayer.frame = CGRectMake(0, 0, 64, 64);
26     shipLayer.position = CGPointMake(0, 150);
27     shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
28     [self.containerView.layer addSublayer:shipLayer];
29     //create the keyframe animation
30     CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
31     animation.keyPath = @"position";
32     animation.duration = 4.0;
33     animation.path = bezierPath.CGPath;
34     [shipLayer addAnimation:animation forKey:nil];
35 }
36 
37 @end
View Code

 

圖8.1 沿著一個貝塞爾曲線移動的宇宙飛船圖片

運行示例,你會發現飛船的動畫有些不太真實,這是因為當它運動的時候永遠指向右邊,而不是指向曲線切線的方向。你可以調整它的affineTransform來對運動方向做動畫,但很可能和其它的動畫衝突。

幸運的是,蘋果預見到了這點,並且給CAKeyFrameAnimation添加了一個rotationMode的屬性。設置它為常量kCAAnimationRotateAuto(清單8.7),圖層將會根據曲線的切線自動旋轉(圖8.2)。

清單8.7 通過rotationMode自動對齊圖層到曲線

 1 - (void)viewDidLoad
 2 {
 3     [super viewDidLoad];
 4     //create a path
 5     ...
 6     //create the keyframe animation
 7     CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
 8     animation.keyPath = @"position";
 9     animation.duration = 4.0;
10     animation.path = bezierPath.CGPath;
11     animation.rotationMode = kCAAnimationRotateAuto;
12     [shipLayer addAnimation:animation forKey:nil];
13 }

圖8.2 匹配曲線切線方向的飛船圖層

虛擬屬性

之前提到過屬性動畫實際上是針對於關鍵路徑而不是一個鍵,這就意味著可以對子屬性甚至是虛擬屬性做動畫。但是虛擬屬性到底是什麼呢?

考慮一個旋轉的動畫:如果想要對一個物體做旋轉的動畫,那就需要作用於transform屬性,因為CALayer沒有顯式提供角度或者方向之類的屬性,代碼如清單8.8所示

清單8.8 用transform屬性對圖層做動畫

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *containerView;
 4 
 5 @end
 6 
 7 @implementation ViewController
 8 
 9 - (void)viewDidLoad
10 {
11     [super viewDidLoad];
12     //add the ship
13     CALayer *shipLayer = [CALayer layer];
14     shipLayer.frame = CGRectMake(0, 0, 128, 128);
15     shipLayer.position = CGPointMake(150, 150);
16     shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
17     [self.containerView.layer addSublayer:shipLayer];
18     //animate the ship rotation
19     CABasicAnimation *animation = [CABasicAnimation animation];
20     animation.keyPath = @"transform";
21     animation.duration = 2.0;
22     animation.toValue = [NSValue valueWithCATransform3D: CATransform3DMakeRotation(M_PI, 0, 0, 1)];
23     [shipLayer addAnimation:animation forKey:nil];
24 }
25 
26 @end
View Code

這麼做是可行的,但看起來更因為是運氣而不是設計的原因,如果我們把旋轉的值從M_PI(180度)調整到2 * M_PI(360度),然後運行程式,會發現這時候飛船完全不動了。這是因為這裡的矩陣做了一次360度的旋轉,和做了0度是一樣的,所以最後的值根本沒變。

現在繼續使用M_PI,但這次用byValue而不是toValue。也許你會認為這和設置toValue結果一樣,因為0 + 90度 == 90度,但實際上飛船的圖片變大了,並沒有做任何旋轉,這是因為變換矩陣不能像角度值那樣疊加。

那麼如果需要獨立於角度之外單獨對平移或者縮放做動畫呢?由於都需要我們來修改transform屬性,實時地重新計算每個時間點的每個變換效果,然後根據這些創建一個複雜的關鍵幀動畫,這一切都是為了對圖層的一個獨立做一個簡單的動畫。

幸運的是,有一個更好的解決方案:為了旋轉圖層,我們可以對transform.rotation關鍵路徑應用動畫,而不是transform本身(清單8.9)。

清單8.9 對虛擬的transform.rotation屬性做動畫

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *containerView;
 4 
 5 @end
 6 
 7 @implementation ViewController
 8 
 9 - (void)viewDidLoad
10 {
11     [super viewDidLoad];
12     //add the ship
13     CALayer *shipLayer = [CALayer layer];
14     shipLayer.frame = CGRectMake(0, 0, 128, 128);
15     shipLayer.position = CGPointMake(150, 150);
16     shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
17     [self.containerView.layer addSublayer:shipLayer];
18     //animate the ship rotation
19     CABasicAnimation *animation = [CABasicAnimation animation];
20     animation.keyPath = @"transform.rotation";
21     animation.duration = 2.0;
22     animation.byValue = @(M_PI * 2);
23     [shipLayer addAnimation:animation forKey:nil];
24 }
25 
26 @end
View Code

結果運行的特別好,用transform.rotation而不是transform做動畫的好處如下:

  • 我們可以不通過關鍵幀一步旋轉多於180度的動畫。
  • 可以用相對值而不是絕對值旋轉(設置byValue而不是toValue)。
  • 可以不用創建CATransform3D,而是使用一個簡單的數值來指定角度。
  • 不會和transform.position或者transform.scale衝突(同樣是使用關鍵路徑來做獨立的動畫屬性)。

transform.rotation屬性有一個奇怪的問題是它其實並不存在。這是因為CATransform3D並不是一個對象,它實際上是一個結構體,也沒有符合KVC相關屬性,transform.rotation實際上是一個CALayer用於處理動畫變換的虛擬屬性。

你不可以直接設置transform.rotation或者transform.scale,他們不能被直接使用。當你對他們做動畫時,Core Animation自動地根據通過CAValueFunction來計算的值來更新transform屬性。

CAValueFunction用於把我們賦給虛擬的transform.rotation簡單浮點值轉換成真正的用於擺放圖層的CATransform3D矩陣值。你可以通過設置CAPropertyAnimationvalueFunction屬性來改變,於是你設置的函數將會覆蓋預設的函數。

CAValueFunction看起來似乎是對那些不能簡單相加的屬性(例如變換矩陣)做動畫的非常有用的機制,但由於CAValueFunction的實現細節是私有的,所以目前不能通過繼承它來自定義。你可以通過使用蘋果目前已近提供的常量(目前都是和變換矩陣的虛擬屬性相關,所以沒太多使用場景了,因為這些屬性都有了預設的實現方式)。


 

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 軟體繪圖 術語繪圖通常在Core Animation的上下文中指代軟體繪圖(意即:不由GPU協助的繪圖)。在iOS中,軟體繪圖通常是由Core Graphics框架完成來完成。但是,在一些必要的情況下,相比Core Animation和OpenGL,Core Graphics要慢了不少。 軟體繪圖不 ...
  • 物理模擬 即使使用了基於定時器的動畫來複制第10章中關鍵幀的行為,但還是會有一些本質上的區別:在關鍵幀的實現中,我們提前計算了所有幀,但是在新的解決方案中,我們實際上實在按需要在計算。意義在於我們可以根據用戶輸入實時修改動畫的邏輯,或者和別的實時動畫系統例如物理引擎進行整合。 Chipmunk 我們 ...
  • 自定義緩衝函數 在第八章中,我們給時鐘項目添加了動畫。看起來很贊,但是如果有合適的緩衝函數就更好了。在顯示世界中,鐘錶指針轉動的時候,通常起步很慢,然後迅速啪地一聲,最後緩衝到終點。但是標準的緩衝函數在這裡每一個適合它,那該如何創建一個新的呢? 除了+functionWithName:之外,CAMe ...
  • 直接寫解決方法吧: 1、將XML里的靜態引入刪除: 2、在代碼里 findViewById 找到 NavigationView,然後引入 Header 和 Menu,再獲取頭部佈局,最後設置監聽事件: 3、完整代碼如下: ...
  • 動畫速度 動畫實際上就是一段時間內的變化,這就暗示了變化一定是隨著某個特定的速率進行。速率由以下公式計算而來: 這裡的變化可以指的是一個物體移動的距離,時間指動畫持續的時長,用這樣的一個移動可以更加形象的描述(比如position和bounds屬性的動畫),但實際上它應用於任意可以做動畫的屬性(比如 ...
  • #CAMediaTiming`協議 CAMediaTiming協議定義了在一段動畫內用來控制逝去時間的屬性的集合,CALayer和CAAnimation都實現了這個協議,所以時間可以被任意基於一個圖層或者一段動畫的類控制。 持續和重覆 我們在第八章“顯式動畫”中簡單提到過duration(CAMed ...
  • 在動畫過程中取消動畫 之前提到過,你可以用-addAnimation:forKey:方法中的key參數來在添加動畫之後檢索一個動畫,使用如下方法: 但並不支持在動畫運行過程中修改動畫,所以這個方法主要用來檢測動畫的屬性,或者判斷它是否被添加到當前圖層中。 為了終止一個指定的動畫,你可以用如下方法把它 ...
  • Feature: 點擊選擇拍照或者打開相冊,選取圖片進行裁剪最後設置為圓形頭像。 Problem: 拍好照片,點擊裁剪,彈Toast“無法載入此圖片”。 Solution: 在裁剪的class裡加兩行代碼 主要代碼如下: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...