6.6 CAScrollLayer 圖層

2021-09-14 16:22 更新

CAScrollLayer

對于一個未轉(zhuǎn)換的圖層,它的bounds和它的frame是一樣的,frame屬性是由bounds屬性自動計算而出的,所以更改任意一個值都會更新其他值。

但是如果你只想顯示一個大圖層里面的一小部分呢。比如說,你可能有一個很大的圖片,你希望用戶能夠隨意滑動,或者是一個數(shù)據(jù)或文本的長列表。在一個典型的iOS應(yīng)用中,你可能會用到UITableView或是UIScrollView,但是對于獨立的圖層來說,什么會等價于剛剛提到的UITableViewUIScrollView呢?

在第二章中,我們探索了圖層的contentsRect屬性的用法,它的確是能夠解決在圖層中小地方顯示大圖片的解決方法。但是如果你的圖層包含子圖層那它就不是一個非常好的解決方案,因為,這樣做的話每次你想『滑動』可視區(qū)域的時候,你就需要手工重新計算并更新所有的子圖層位置。

這個時候就需要CAScrollLayer了。CAScrollLayer有一個-scrollToPoint:方法,它自動適應(yīng)bounds的原點以便圖層內(nèi)容出現(xiàn)在滑動的地方。注意,這就是它做的所有事情。前面提到過,Core Animation并不處理用戶輸入,所以CAScrollLayer并不負責將觸摸事件轉(zhuǎn)換為滑動事件,既不渲染滾動條,也不實現(xiàn)任何iOS指定行為例如滑動反彈(當視圖滑動超多了它的邊界的將會反彈回正確的地方)。

讓我們來用CAScrollLayer來常見一個基本的UIScrollView替代品。我們將會用CAScrollLayer作為視圖的宿主圖層,并創(chuàng)建一個自定義的UIView,然后用UIPanGestureRecognizer實現(xiàn)觸摸事件響應(yīng)。這段代碼見清單6.10. 圖6.11是運行效果:ScrollView顯示了一個大于它的frameUIImageView。

清單6.10 用CAScrollLayer實現(xiàn)滑動視圖

#import "ScrollView.h"
#import  @implementation ScrollView
+ (Class)layerClass
{
    return [CAScrollLayer class];
}

- (void)setUp
{
    //enable clipping
    self.layer.masksToBounds = YES;

    //attach pan gesture recognizer
    UIPanGestureRecognizer *recognizer = nil;
    recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
    [self addGestureRecognizer:recognizer];
}

- (id)initWithFrame:(CGRect)frame
{
    //this is called when view is created in code
    if ((self = [super initWithFrame:frame])) {
        [self setUp];
    }
    return self;
}

- (void)awakeFromNib {
    //this is called when view is created from a nib
    [self setUp];
}

- (void)pan:(UIPanGestureRecognizer *)recognizer
{
    //get the offset by subtracting the pan gesture
    //translation from the current bounds origin
    CGPoint offset = self.bounds.origin;
    offset.x -= [recognizer translationInView:self].x;
    offset.y -= [recognizer translationInView:self].y;

    //scroll the layer
    [(CAScrollLayer *)self.layer scrollToPoint:offset];

    //reset the pan gesture translation
    [recognizer setTranslation:CGPointZero inView:self];
}
@end

圖6.11 用UIScrollView創(chuàng)建一個湊合的滑動視圖

不同于UIScrollView,我們定制的滑動視圖類并沒有實現(xiàn)任何形式的邊界檢查(bounds checking)。圖層內(nèi)容極有可能滑出視圖的邊界并無限滑下去。CAScrollLayer并沒有等同于UIScrollViewcontentSize的屬性,所以當CAScrollLayer滑動的時候完全沒有一個全局的可滑動區(qū)域的概念,也無法自適應(yīng)它的邊界原點至你指定的值。它之所以不能自適應(yīng)邊界大小是因為它不需要,內(nèi)容完全可以超過邊界。

那你一定會奇怪用CAScrollLayer的意義到底何在,因為你可以簡單地用一個普通的CALayer然后手動適應(yīng)邊界原點啊。真相其實并不復(fù)雜,UIScrollView并沒有用CAScrollLayer,事實上,就是簡單的通過直接操作圖層邊界來實現(xiàn)滑動。

CAScrollLayer有一個潛在的有用特性。如果你查看CAScrollLayer的頭文件,你就會注意到有一個擴展分類實現(xiàn)了一些方法和屬性:

- (void)scrollPoint:(CGPoint)p;
- (void)scrollRectToVisible:(CGRect)r;
@property(readonly) CGRect visibleRect;

看到這些方法和屬性名,你也許會以為這些方法給每個CALayer實例增加了滑動功能。但是事實上他們只是放置在CAScrollLayer中的圖層的實用方法。scrollPoint:方法從圖層樹中查找并找到第一個可用的CAScrollLayer,然后滑動它使得指定點成為可視的。scrollRectToVisible:方法實現(xiàn)了同樣的事情只不過是作用在一個矩形上的。visibleRect屬性決定圖層(如果存在的話)的哪部分是當前的可視區(qū)域。如果你自己實現(xiàn)這些方法就會相對容易明白一點,但是CAScrollLayer幫你省了這些麻煩,所以當涉及到實現(xiàn)圖層滑動的時候就可以用上了。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號