Ben yerine bir çubuk grafik animasyon uygulamak CALayer
, CAReplicatorLayer
ve CABasicAnimation
kullanıyorum. Çubuk grafik, CALayer
ile küçük dikdörtgenler halinde oluşturduğum "segmentler" den oluşur. Sonra onları bir döngü içinde CAReplicatorLayer
'a bir alt katman olarak eklerim. Son olarak, dikdörtgeni tablodaki yerine bırakan her küçük dikdörtgen için bir animasyon ekliyorum. İşte kCAMediaTimingFunctionEaseIn'ın bu kullanımıyla ilgili bir sorun var mı?
Ve işte animasyon ortasında neye benzediği: Burada
kılacak yöntem var gerçekleşmesi:
#define BLOCK_HEIGHT 6.0f
#define BLOCK_WIDTH 8.0f
@interface TCViewController()
@property (nonatomic, strong) NSMutableArray * blockLayers; // blocks that fall from the sky
@property (nonatomic, strong) NSMutableArray * replicatorLayers; // replicator layers that will replicate the blocks into position
@end
@implementation TCViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
self.blockLayers = [NSMutableArray array];
self.replicatorLayers = [NSMutableArray array];
NSArray * dataBlocksData = @[@1,@2,@3,@1,@5,@2,@11,@14,@5,@12,@10,@3,@7,@6,@3,@4,@1];
__block CGFloat currentXPosition = 0.0f;
[dataBlocksData enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
currentXPosition += BLOCK_WIDTH + 2.0f;
if (obj.integerValue == 0) return;
// replicator layer for data blocks in a column
CAReplicatorLayer * replicatorLayer = [[CAReplicatorLayer alloc] init];
replicatorLayer.frame = CGRectMake(currentXPosition, 0.0f, BLOCK_WIDTH, 200.0f);
// single data block layer (must be new for each replicator layer. can't reuse existing layer)
CALayer * blockLayer = [[CALayer alloc] init];
blockLayer.frame = CGRectMake(0, 200-BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);
blockLayer.backgroundColor = [UIColor whiteColor].CGColor;
[replicatorLayer addSublayer:blockLayer];
replicatorLayer.instanceCount = obj.integerValue;
replicatorLayer.instanceDelay = 0.1f;
replicatorLayer.instanceTransform = CATransform3DMakeTranslation(0, -BLOCK_HEIGHT, 0); // negative height moves back up the column
[self.blockLayers addObject:blockLayer];
[self.replicatorLayers addObject:replicatorLayer];
}];
}
- (void)viewDidLayoutSubviews {
// add replicator layers as sublayers
[self.replicatorLayers enumerateObjectsUsingBlock:^(CAReplicatorLayer * obj, NSUInteger idx, BOOL *stop) {
[self.view.layer addSublayer:obj];
}];
}
- (void)viewDidAppear:(BOOL)animated {
// add animations to each block layer
[self.blockLayers enumerateObjectsUsingBlock:^(CALayer * obj, NSUInteger idx, BOOL *stop) {
// position animation
CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
animation.fromValue = @(-300);
animation.toValue = @(0);
animation.duration = 1.0f;
animation.fillMode = kCAFillModeBoth;
animation.removedOnCompletion = NO;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
[obj addAnimation:animation forKey:@"falling-block-animation"];
}];
}
Son olarak, işte yakalayıcı. Hiçbir timingFunction
, bir Linear
işlev veya bir EaseIn
belirtirseniz animasyonlar tamamen tamamlanmaz çalışır. Bloklar tamamen yerine düşmez. Bitişe yakın gibi görünüyorlar ama tam olarak değil. Sadece bir kare veya iki kapalı. -viewDidAppear:
zamanlama fonksiyonu atama aktarır ve bu garabeti alırsınız:
Devam et, bir deneyin. Hatta tam bir EaseIn
işlevi gibidir kontrol noktaları ile bir işlev (link) belirterek çalıştı:
EaseOut
ve
Default
zamanlama fonksiyonları iyi çalışır ancak stil işlevinde bir kolaylık daha uzun süren görünmektedir Nedense
// use control points for an EaseIn timing:
animation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.42 :0.00 :1.0 :1.0];
// or simply specify the ease in timing function:
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
, görsel olarak, belki de enterpolasyon eğrisinin uzunluğu nedeniyle?
- bu yapıların üzerinde döngü ve sadece 1 katman ve aynı animasyon ile 1 çoğaltıcı katmanını kullanmama:
Sorunu daraltmak için birçok şeyi denedim. Bununla demek istediğim, sadece bir sütun hareketlendirmek. Şanssız. Döngü sorun değil.
- oluşturulmasını koyun, alt katman-ekleme ve
-viewDidAppear
tüm kodu animasyon ekleyerek. Animasyonlar görünümün yaşam döngüsünde daha önce veya daha sonra eklendiyse, bir fark yaratmıyor gibi görünmüyordu. - Yapılarım için özellikleri kullanma. Fark yok.
- benim yapıların özelliklerini kullanmama. Yine, fark yok. Doğru "nihai" halde sütun bırakacak şekilde animasyon tamamlanması için
- Eklenen geri aramalar animasyon kaldırın. Bu iyi değildi ama denemeye değer.
- sorunu hem iOS 6 ve gerçekten bir şey için en iyi şekilde görünmesini animasyon yerine oturuyor çünkü bir
EaseIn
zamanlama işlevi kullanmak isteyen
7. mevcuttur. Ben de CAReplicatorLayer
kullanmak istiyorum çünkü yapmak istediğim şeyi yapıyor.
EaseIn
zamanlama işlevlerini kullanırken kullandığım gibi mi? Bu bir hata mı?
'removedOnCompletion = NO' lütfen kullanmayın. Animasyonlar yapmanın kötü bir yolu. İnsanlara, SO cevaplarında görmediklerinde bile kötü bir fikir olduğuna ikna edebilecek yeterince zamanım var. OP'nin bu soruyu kullandığını biliyorum, ama hepimiz iyi bir izci olabiliriz ve kamp alanını oraya vardığımız zamandan daha iyi bir durumda bırakabiliriz. –
Tamamen katılıyorum 'removedOnCompletion = NO' kötü bir fikir, ancak bir CAReplicatorLayer'daki bir animasyon için tamamen gerekli. Aksi halde, son çoğaltılan katman tamamen oynatılmadan önce animasyon kaldırılabilir. Buradaki doğru çözümün, time + (instanceCount - 1) * instanceDelay'de bir zamanlayıcıyı ateşlemek ve o anda el ile animasyonu kaldırmak olduğunu düşünüyorum. – GBegen