通過UIKit座標系來全面掌握iOS中的UIScrollView組件_IOS

來源:互聯網
上載者:User

感謝UIKit的座標系統特性,使我們之花了30幾行代碼就能重現UIScrollView的精華,當然真正的UIScrollView要比我們所做的複雜的多,反彈效果,動量滾動,放大試圖,還有代理方法,這些特性我們沒有在這裡涉及到。
首先,讓我們先來瞭解一下UIKit中的座標系是怎麼工作的。如果你只對滾動試圖的代碼實現感興趣可以放心跳過下一小節。UIKit座標系每一個View都定義了他自己的座標系統。如下圖所示,x軸指向右方,y軸指向下方:

注意這個邏輯座標系並不關注包含在其中View的寬度和高度。整個座標系沒有邊界向四周無限延伸.我們在座標系中放置四個子View。每一次色塊代表一個View:

添加View的代碼實現如下:

複製代碼 代碼如下:

UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
redView.backgroundColor = [UIColor colorWithRed:0.815 green:0.007
    blue:0.105 alpha:1];
 
UIView *greenView = [[UIView alloc] initWithFrame:CGRectMake(150, 160, 150, 200)];
greenView.backgroundColor = [UIColor colorWithRed:0.494 green:0.827
    blue:0.129 alpha:1];
 
UIView *blueView = [[UIView alloc] initWithFrame:CGRectMake(40, 400, 200, 150)];
blueView.backgroundColor = [UIColor colorWithRed:0.29 green:0.564
    blue:0.886 alpha:1];
 
UIView *yellowView = [[UIView alloc] initWithFrame:CGRectMake(100, 600, 180, 150)];
yellowView.backgroundColor = [UIColor colorWithRed:0.972 green:0.905
    blue:0.109 alpha:1];
 
[mainView addSubview:redView];
[mainView addSubview:greenView];
[mainView addSubview:blueView];
[mainView addSubview:yellowView];

bounds
Apple關於UIView的文檔中是這樣描述bounds屬性的:

bounds矩形…描述了該視圖在其自身座標系中的位置和大小。

一個View可以被看作是定義在其所在座標系平面上的一扇窗戶或者說是一個矩形的可視地區。View的邊界表明了這個矩形可視地區的位置和大小。

假設我們的View寬320像素,高480像素,原點在(0,0)。那麼這個View就變成了整個座標系平面的觀察口,它展示的只是整個平面的一小部分。位於該View邊界外的地區依然存在,只是被隱藏起來了。

一個View提供了其所在平面的一個觀察口。View的bounds矩形描述了這個可是地區的位置和大小。

Frame
接下來我們來試著修改bounds的原點座標:

複製代碼 代碼如下:

CGRect bounds = mainView.bounds;
bounds.origin = CGPointMake(0, 100);
mainView.bounds = bounds;


當我們把bound原點設為(0,100)後,整個畫面看起來就像這樣:

修改bounds的原點就相當與在平面上移動這個可視地區。

看起來好像是這個View向下移動了100像素,在這個View自己的座標系中這確實沒錯。不過這個View真正位於螢幕上的位置(更準確的說在其父View上的位置)其實沒有改變,因為這是由View的frame屬性決定的,它並沒有改變:

frame矩形…定義了這個View在其父View座標系中的位置和大小。

由於View的位置是相對固定的,你可以把整個座標平面想象成我們可以上下拖動的透明幕布,把這個View想象成我們觀察座標平面的視窗。調整View的Bounds屬性就相當於拖動這個幕布,那麼下方的內容就能在我們View中被觀察到:

修改bounds的原點座標也相當於把整個座標系向上拖動,因為View的frame沒由變過,所以它相對於父View的位置沒有變化過。

其實這就是UIScrollView滑動時所發生的事情。注意從一個使用者的角度來看,他以為時這個View中的子View在移動,其實他們的在座標系中位置(他們的frame)沒有發生過變化。

打造你的UIScrollView
一個scroll view並不需要其中子View的座標來使他們滾動。唯一要做的就是改變他的bounds屬性。知道了這一點,實現一個簡單的scroll view就沒什麼困難了。我們用一個gesture recognizer來識別使用者的拖動操作,根據使用者拖動的位移量來改變bounds的原點:

複製代碼 代碼如下:

// CustomScrollView.h
@import UIKit;
 
@interface CustomScrollView : UIView
 
@property (nonatomic) CGSize contentSize;
 
@end

複製代碼 代碼如下:
 
// CustomScrollView.m
#import "CustomScrollView.h"
 
@implementation CustomScrollView
 
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self == nil) {
        return nil;
    }
    UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc]
        initWithTarget:self action:@selector(handlePanGesture:)];
    [self addGestureRecognizer:gestureRecognizer];
    return self;
}
 
- (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer
{
    CGPoint translation = [gestureRecognizer translationInView:self];
    CGRect bounds = self.bounds;
 
    // Translate the view's bounds, but do not permit values that would violate contentSize
    CGFloat newBoundsOriginX = bounds.origin.x - translation.x;
    CGFloat minBoundsOriginX = 0.0;
    CGFloat maxBoundsOriginX = self.contentSize.width - bounds.size.width;
    bounds.origin.x = fmax(minBoundsOriginX, fmin(newBoundsOriginX, maxBoundsOriginX));
 
    CGFloat newBoundsOriginY = bounds.origin.y - translation.y;
    CGFloat minBoundsOriginY = 0.0;
    CGFloat maxBoundsOriginY = self.contentSize.height - bounds.size.height;
    bounds.origin.y = fmax(minBoundsOriginY, fmin(newBoundsOriginY, maxBoundsOriginY));
 
    self.bounds = bounds;
    [gestureRecognizer setTranslation:CGPointZero inView:self];
}
 
@end

和真正的UIScrollView一樣,我們的類也有一個contentSize屬性,你必須從外部來設定這個值來指定可以滾動的地區,當我們改變bounds的大小時我們要確保設定的值是有效。

結果:

UIScrollView常用操作方法整理

複製代碼 代碼如下:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //  建立一個滾動視圖
    self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64, 320, 568-64)];
    //  設定代理
    self.scrollView.delegate = self;
    self.scrollView.backgroundColor = [UIColor redColor];
    [self.view addSubview:_scrollView];
    /**
     *  CGPoint contentOffSet                       監控目前滾動的位置
     *  CGSize contentSize                          滾動範圍大小(主屬性)
     *  UIEdgeInsets contentInset                   視圖在scrollView中的位置
     *  BOOL directionalLockEnabled                    指定控制項是否只能在一個方向上滾動
     *  BOOL bounces                                控制控制項遇到邊框是否反彈
     *  BOOL alwaysBounceVertical                    控制垂直方向遇到邊框是否反彈
     *  BOOL alwaysBounceHorizontal                    控制水平方向遇到邊框是否反彈
     *  BOOL pagingEnabled                            控制控制項是否整頁翻動
     *  BOOL scrollEnabled                            控制控制項是否能滾動
     *  BOOL showsHorizontalScrollIndicator            控制是否顯示水平方向的捲軸
     *  BOOL showsVerticalScrollIndicator            控制是否顯示垂直方向的捲軸
     *  UIEdgeInsets scrollIndicatorInsets            指定捲軸在scrollerView中的位置
     *  UIScrollViewIndicatorStyle indicatorStyle    設定捲軸的樣式
     *  float decelerationRate                        改變scrollerView的減速點位置
     *  BOOL tracking                                監控當前目標是否正在被跟蹤
     *  BOOL dragging                                監控當前目標是否正在被拖拽
     *  BOOL decelerating                            監控當前目標是否正在減速
     *  BOOL delaysContentTouches                    控制視圖是否延時調用開始滾動的方法
     *  BOOL canCancelContentTouches                控制控制項是否接觸取消touch的事件
     *  float minimumZoomScale                        縮放的最小比例
     *  float maximumZoomScale                        縮放的最大比例
     *  float zoomScale                                設定變化比例
     *  BOOL bouncesZoom                            控制縮放的時候是否會反彈
     *  BOOL zooming                                判斷控制項的大小是否正在改變
     *  BOOL zoomBouncing                            判斷是否進行中縮放反彈
     *  BOOL scrollsToTop                            控制控制項滾動到頂部
     */

    //  提示使用者,在介面建立的時候,水平捲軸或者垂直捲軸會出現一次閃現效果
    [self.scrollView flashScrollIndicators];
    //  位移帶動畫效果
    [self.scrollView setContentOffset:CGPointMake(320, 0) animated:YES];

}

#pragma mark UIScrollViewDelegate
//  只要滾動了就會觸發
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
{


}

//  開始拖拽視圖
// 當開始滾動視圖時,執行該方法。一次有效滑動(開始滑動,滑動一小段距離,只要手指不鬆開,只算一次滑動),只執行一次。
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
{

}

// 滑動視圖,當手指離開螢幕那一霎那,調用該方法。一次有效滑動,只執行一次。
// decelerate,指代,當我們手指離開那一瞬後,視圖是否還將繼續向前滾動(一段距離),經過測試,decelerate=YES
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
{

}

//  將開始降速時
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;
{

}

// 滾動視圖減速完成,滾動將停止時,調用該方法。一次有效滑動,只執行一次。
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
{

}

//  滾動動畫停止時執行,代碼改變時出發,也就是setContentOffset改變時
// 當滾動視圖動畫完成後,調用該方法,如果沒有動畫,那麼該方法將不被調用
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;
{

}

//  設定放大縮小的視圖,要是uiscrollview的subview , 返回將要縮放的UIView對象。要執行多次
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;
{

    return nil;
}

// 當將要開始縮放時,執行該方法。一次有效縮放,就只執行一次。
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
    NSLog(@"scrollViewWillBeginZooming");
}

// 當縮放結束後,並且縮放大小回到minimumZoomScale與maximumZoomScale之間後(我們也許會超出縮放範圍),調用該方法。
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(double)scale;
{

}

//  如果你不是完全滾動到滾軸視圖的頂部,你可以輕點狀態列,那個可視的滾軸視圖會一直滾動到頂部,那是預設行為,你可以通過該方法返回NO來關閉它
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;
{

    return YES;
}

//  已經滑動到頂部
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;
{

}


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.