2010-12-13 63 views
0

我試圖爲iPad應用程序實現水平滾動視圖。滾動視圖顯示一系列圖像。滾動後,當滾動視圖停止時,我希望圖像沿着水平線的特定點對齊。爲此,我嘗試了兩種方法:停止在特定位置的UIScrollView

1)禁用UIScrollView的滾動,而是實現PanGestureRecogniser,它將檢測「滑動/拖動」運動的平移和速度,並相應地將滾動視圖的內容偏移設置爲所需的預定點數。但是,這裏的問題在於,如果用戶緩慢地拖動滾動視圖,則滾動視圖運動非常不穩定,因爲滾動視圖的所檢索的x座標在手指按下的點周圍來回跳動。例如:當手指沿60-70移動時,x值從50到70。我如何使滾動視圖的運動平滑?

2)啓用UIScrollView的滾動並檢查減速結束,然後設置滾動視圖的內容偏移量以將其調整到必要的位置。但問題在於,滾動視圖只有在停止減速之後纔會調整到最終位置,並且存在可見的延遲,並且該動畫看起來不太好。有沒有辦法可以檢測滾動視圖何時停止滾動,然後調整其位置而不是等待滾動結束。從某些論壇上閱讀的內容來看,這是不可能的。

3)在這種情況下,分頁滾動視圖不起作用,因爲我不希望圖像的整個寬度被滾出。

有沒有人有關於如何實現上述功能的任何想法。

回答

1

您實際上仍然可以使用分頁滾動視圖來執行此操作。您只需將clipsToBounds設置爲NO(以便滾動視圖中的內容可以在其幀外呈現),然後將frame設置爲所需的對齊步驟。

例如,如果要對齊的200的倍數滾動視圖,你可以這樣做:

scrollView.pagingEnabled = YES; 
scrollView.clipsToBounds = NO; 

// horizontally center scroll view with a width of 200 and the parent's height 
scrollView.frame = CGRectMake(
    floor((parentView.bounds.size.width - 200)/2), 
    0, 
    200, 
    parentView.bounds.size.height 
); 

[parentView addSubview:scrollView]; 
+0

真。但在這種情況下,「可滾動/可滑動」區域的寬度也會被限制爲200?這意味着用戶將無法滑過圖像渲染的整個水平部分,並且僅限於在200個單位內滾動/滑動。我希望用戶能夠滾動滾動視圖的整個寬度。 – Nathan 2010-12-13 13:41:56

+0

你可以通過繼承'UIScrollView'並重寫'hitTest:withEvent:'來​​回滾'YES'來區分這個問題,在你想要滾動的區域內(在這個例子中是父視圖的全部寬度)。 – 2010-12-13 16:20:19

+0

好的,我應該嘗試。但是,通過Paging滾動視圖來解決另一個基本問題。如果用戶進行「快速滑動」,那麼只有一個圖像(或一組固定圖像)每次都會向右滾動?它不會像一個自由滾動視圖,每次滾動出來的圖像數量會根據滑動的距離和速度而變化。對不起,如果它看起來像我在這裏扮演魔鬼的倡導者,但我只是想獲得正確的功能。 – Nathan 2010-12-15 07:49:14

2

我已經有垂直滾動視圖所面臨的同樣的問題,使用的方法2.即使如果這個問題很老,我沒有在這裏找到解決方案,並且覺得它會很好回答。

簡短回答是UIScrollViewDelegate協議中的scrollViewWillEndDragging:withVelocity:targetContentOffset: 方法。

當用戶完成滾動並且動畫開始減速時,它會爲您提供targetContentOffset。您可以在此方法中更改targetContentOffset,以便動畫將盡可能地結束。你的工作只是計算目標位置。

這裏是我創建的UIView子類。我想創建一個UIPickerView類,但我想它停止在特定位置(如日期選擇器)

我創建了一個符合UIScrollViewDelegate的UIView子類。在這個UIView中,我添加了一個滾動視圖。這個滾動視圖將包含UILabel實例。小心我使用ARC,所以我不釋放任何東西。

#import <UIKit/UIKit.h> 

@protocol MyPickerViewDataSource <NSObject> 

-(NSUInteger)numberOfRowsForSender:(id)sender; 
-(NSString *)titleForRowAtIndex:(NSUInteger)rowIndex sender:(id)sender; 

@end 

@interface MyPickerView : UIView <UIScrollViewDelegate> 

@property (weak, nonatomic) id<MyPickerViewDataSource> dataSource; 

@end 

實施:

#import "MyPickerView.h" 

#define CONTENT_ROW_HEIGHT 30 

typedef enum { 
    ScrollDirectionUp, 
    ScrollDirectionDown 
} ScrollDirection; 

@interface MyPickerView() { 

    int topOffset; 
    int bottomOffset; 
    int lastContentOffset; 
    int targetLabelIndex; 
    ScrollDirection scrollDirection; 
} 

@implementation PickerView 

- (void)initSetup { 
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(self.frame.origin.x,self.frame.origin.y, self.frame.size.width, self.frame.size.height)]; 
self.scrollView.delegate = self; 
self.scrollView.showsHorizontalScrollIndicator = NO; 
self.scrollView.showsVerticalScrollIndicator = NO; 
self.scrollView.userInteractionEnabled = YES; 
[self addSubview:self.scrollView]; 

targetLabelIndex = 0; 

topOffset = (self.scrollView.frame.size.height/2)-CONTENT_ROW_HEIGHT/2; 
bottomOffset = topOffset; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder { 
    self = [super initWithCoder:aDecoder]; 
    if(self) { 
     [self initSetup]; 
    } 
    return self; 
} 

- (id)initWithFrame:(CGRect)frame { 
    self = [super initWithFrame:frame]; 
    if(self) { 
     [self initSetup]; 
    } 
    return self; 
} 

- (void)layoutSubviews { 

    [super layoutSubviews]; 

    NSUInteger numberOfRows = [self.dataSource numberOfRowsForSender:self]; 

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, topOffset+numberOfRows*CONTENT_ROW_HEIGHT+bottomOffset); 

    for (int index = 0; index < numberOfRows; index++) 
    { 
     UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(self.scrollView.frame.origin.x, 
                    topOffset+index*CONTENT_ROW_HEIGHT, 
                    self.scrollView.frame.size.width, 
                    CONTENT_ROW_HEIGHT)]; 

     label.backgroundColor = [UIColor clearColor]; 
     label.textColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; 
     label.text = [self.dataSource titleForRowAtIndex:index sender:self]; 

     [self.scrollView addSubview:label]; 
    } 

    [(UILabel *)[self.scrollView.subviews objectAtIndex:targetLabelIndex] setTextColor:[UIColor blueColor]]; 
} 

- (void)reloadData { 

    NSUInteger numberOfRows = [self.dataSource numberOfRowsForSender:self]; 

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, numberOfRows*CONTENT_ROW_HEIGHT); 

    [self.scrollView setContentOffset:CGPointMake(0.0, 0.0) animated:NO]; 

    [self layoutSubviews]; 
} 

#pragma mark - UIScrollViewDelegate 

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { 

    if(lastContentOffset>self.scrollView.contentOffset.y) { 

     scrollDirection = ScrollDirectionUp; 
    } 
    else { 

     scrollDirection = ScrollDirectionDown; 
    } 

    lastContentOffset = self.scrollView.contentOffset.y; 
} 

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { 

    targetLabelIndex = (targetContentOffset->y/CONTENT_ROW_HEIGHT)+1; 

    if(scrollDirection==ScrollDirectionUp && targetLabelIndex>0) { 

     targetLabelIndex--; 
    } 

    targetContentOffset->y = targetLabelIndex*CONTENT_ROW_HEIGHT; 

    [(UILabel *)[self.scrollView.subviews objectAtIndex:targetLabelIndex] setTextColor:[UIColor blueColor]]; 
} 

@end 
+0

感謝您發佈此信息;我遇到了與UICollectionView相同的問題。我注意到方法文檔提出了這種方法:「您的應用程序可以更改targetContentOffset參數的值,以調整滾動視圖完成其滾動動畫的位置。」 – JLundell 2013-04-08 16:37:53