2014年7月22日

IOS UIScrollView 的使用


有時我們會希望能在畫面上顯示較多的訊息,這些訊息可能會超過螢幕大小。這時就需要用到 scrollview 了。scrollview 可以在有限的畫面上顯示較多的資料,例如個人資料,設定畫面等等。

contentsize

contentsize 顧名思義就是 scrollview 所包含的內容大小,也可以說是可滑動範圍。IOS UIScrollView 不像 Android 的 scrollview 一樣,雖然他一樣會自動偵測內容大小,但必須每個元件都要有固定寬 / 高,否則就必須手動設定。
通常我們會先將 scrollview 所包含的元件建立完,之後再設置 contentsize,這樣在滑動的時候才能看到完整資料。若設置太小,下面的資料可能就會有部分資料無法顯示,若設置太大,則會在下方出現大量空白區域。
上圖為 contentsize 設定太小的結果,下方資料無法顯示
上圖為 contentsize 設定太大的結果,下方留下大片空白區域

contentsize not work

若您的畫面是使用 storyboard 設計,可能會出現在 controller 中不管怎麼設定 contentsize,它都還是 storyboard 中的設定,即使已經在 viewDidAppear 中設定,卻還是沒用的情況。(猜測可能系統在執行完 viewDidAppear 後,才載入 storyboard 中的一些設定,導致這種情況,但官方沒有確切的說明 storyboard 在顯示的流程...),這時建議改在 viewDidLayoutSubviews 中做設定

//失敗
- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:YES];
    if(self.reloadData.intValue == 1){
        if(cgroupList.count > 0){
            [editCgroupListDelegate reloadDataWithTableView:self.tv_group list:cgroupList];
            float groupListHeight = [self setListHight:self.tv_group delegate:editCgroupListDelegate listCount:[cgroupList count]];
            NSLog(@"updateGroupListUI profileview height:%f", height_profileview+groupListHeight);

     //設定 scrollview contentSize
            self.scview_profile.contentSize = CGSizeMake(self.view_profile.frame.size.width, height_profileview+groupListHeight+height_phoneList);//(phoneCellHeight*phoneList.count)

            NSLog(@"tableview phoneList height:%f", height_phoneList);
            self.tv_group.hidden = NO;
        }else{
            self.tv_group.hidden = YES;
        }
    }
}


//成功,但會進入兩次,可以加些 flag 去過濾
- (void)viewDidLayoutSubviews{
    [super viewDidLayoutSubviews];
    if(self.reloadData.intValue == 1){
        if(cgroupList.count > 0){
            [editCgroupListDelegate reloadDataWithTableView:self.tv_group list:cgroupList];
            float groupListHeight = [self setListHight:self.tv_group delegate:editCgroupListDelegate listCount:[cgroupList count]];
            NSLog(@"updateGroupListUI profileview height:%f", height_profileview+groupListHeight);
            
            //設定 scrollview contentSize
            self.scview_profile.contentSize = CGSizeMake(self.view_profile.frame.size.width, height_profileview+groupListHeight+height_phoneList);//(phoneCellHeight*phoneList.count)
            
            NSLog(@"tableview phoneList height:%f", height_phoneList);
            self.tv_group.hidden = NO;
        }else{
            self.tv_group.hidden = YES;
        }
    }
}

viewDidLayoutSubviews 執行順序


//進入
viewWillAppear
viewDidLayoutSubviews
viewDidAppear
viewDidLayoutSubviews

//換頁
viewWillDisappear
viewDidLayoutSubviews
viewDidDisappear

scrollview 的排版

如下圖,一般來說我們會再 scrollview 中放置一個 view,當作 contentview,在將要顯示的元件放在 contentview 中。這種排版的好處是,在設置 contentsize 的時候,可以直接抓 contentview 的寬 / 高。

上圖圈起來的部分,是 contentview 的高度

上圖圈起來的部分,是 contentview 的高度
※ 若 contentview 中所有元件有固定的寬高,那甚至可以不用設置 scrollview 的 contentsize,系統會自行計算 contentsize 的寬 / 高

scrollview 中元件有註冊 event,在畫面上也看的到元件,卻永遠點不到?

當您遇到上述問題時,就該檢查一下您 scrollview 中元件的排版了。
※ 注意!只有在 contentview 中的元件,才能觸發 event
解決辦法:將您的 contentview 上色,執行並查看剛剛的元件是否包含在 contentview 中
上圖中,下方白色區塊,因為元件不在 contentview 中,所以無法觸發 event
上圖中,所有元件都在 contentview 中,所以可以正常觸發 event

References