問題描述
我使用 UIScrollView 作為我的分頁滾動視圖,pagesScrollView
.在其中,我放置了專門用于縮放的單個 UIScrollView.在其中的每一個中,我都有一個視圖,它是應該可以縮放的頁面項目.所有這些都在帶有半透明導航欄的 UINavigationController 中.
I'm using a UIScrollView as my paging scroll view, pagesScrollView
. Inside that, I put individual UIScrollViews which are used exclusively for zooming. Inside each of those, I have one view which is the page item which should be zoomable. All of that is inside a UINavigationController with a translucent navbar.
我的 pagesScrollView
有 contentInset.top = 64
和 bounds.origin.y = -64
(這對我來說似乎很奇怪,但那是系統為我自動設置的內容),這很好用.我的屏幕看起來很棒!
My pagesScrollView
has contentInset.top = 64
and bounds.origin.y = -64
(that seems weird to me, but that's what the system is setting automatically for me), and this works just fine. My screen looks great!
但是,在我滾動 pagesScrollView
一點點之后,只要調用 scrollViewWillEndDragging
,pagesScrollView
就會開始動畫更改bounds.origin.y = -64
到 bounds.origin.y = 0
這會導致我的頁面項目被導航欄遮擋.
However, after I scroll the pagesScrollView
even a tiny bit, as soon as scrollViewWillEndDragging
is called, the pagesScrollView
begins an animated change from bounds.origin.y = -64
to bounds.origin.y = 0
which causes my page items to be obscured by the navbar.
左邊是加載時的樣子,右邊是我拖動幾個像素然后松開后的樣子,它在導航欄下向上滑動(因為 bounds.origin.y 去了到 0).
On the left is what it looks like when it loads, on the right is what it looks like after I drag just a few pixels and then let go, it slides up under the navbar (because the bounds.origin.y goes to 0).
問題是我沒有任何代碼可以改變邊界,并且我在各種滾動委托方法中沒有任何代碼可以做任何事情.我添加了一堆滾動委托方法,并且剛剛添加了 NSLog(),這樣我就可以知道更改發生的時間/地點,但它并沒有在我的代碼中的任何地方發生.
The problem is that I don't have any code that is altering the bounds and I don't have any code in the various scroll delegate methods that do anything. I've added a bunch of scroll delegate methods and just added NSLog()s so I can figure out when/where the change is happening, but it's not happening anywhere in my code.
所以,我不知道我可以向您展示什么代碼來幫助您幫助我.
So, I don't know what code I can show you to help you help me.
我從頭開始構建了一個新項目以刪除所有其他變量.我將一個裸 UIViewController 放入 UINavigationController.我將一個 UIScrollView 放入我的視圖中,整個視圖的大小.以下代碼是整個項目.
I built a new project from scratch to remove all other variables.. I put a bare UIViewController into a UINavigationController. I put a UIScrollView into my View the entire size of the view. The following code is the entire project.
事實證明,問題(如下所述)僅在 UIScrollView 上啟用 PAGING 后才會出現!什么?:)
It turns out the issue (described below) only appears once PAGING IS ENABLED on the UIScrollView! Wtf? :)
這里是一個下載基本項目的鏈接,其中只有幾行代碼來演示該問題.只需單擊滾動視圖,您就會看到它隨著邊界的變化而向上移動.http://inadaydevelopment.com/stackoverflow/WeirdScrollViews.zip
Here is a link to download a basic project with only a few lines of code which demonstrates the problem. Just click in the scrollview and you'll see it shift up as the bounds change. http://inadaydevelopment.com/stackoverflow/WeirdScrollViews.zip
如何在滾動視圖上啟用分頁,而不會在滾動和移動導航欄下的所有內容時出現邊界問題?
How can I have paging enabled on my scrollview without the bounds freaking out during scrolling and shifting everything under the nav bar?
可以將導航欄設置為不透明并避免問題,但理想的情況是具有標準的 iOS7 行為,以便在內容視圖縮放后,然后允許內容位于導航欄下方并應通過半透明正常.
It's possible to set the navbar to opaque and the problem is avoided, but the ideal is to have standard iOS7 behavior so that after the content view is zoomed, THEN the content is allowed to be under the navbar and should show through the translucency normally.
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSArray *colors = @[
[UIColor blueColor],
[UIColor orangeColor],
[UIColor magentaColor],
];
NSArray *zoomerColors = @[
[UIColor greenColor],
[UIColor yellowColor],
[UIColor purpleColor],
];
self.scroller.pagingEnabled = YES;
[self.scroller setContentSize:CGSizeMake(self.scroller.frame.size.width*colors.count, self.scroller.frame.size.height)];
CGRect subviewFrame = CGRectMake(0, 0, 160, 240);
for (int index=0; index < colors.count; index++) {
UIColor *color = [colors objectAtIndex:index];
UIColor *zoomerColor = [zoomerColors objectAtIndex:index];
UIView *subview = [[UIView alloc] initWithFrame:subviewFrame];
subview.backgroundColor = color;
CGRect zoomerFrame = CGRectMake(index*self.scroller.frame.size.width, 0, self.scroller.frame.size.width, self.scroller.frame.size.height);
UIScrollView *zoomer = [[UIScrollView alloc] initWithFrame:zoomerFrame];
[zoomer addSubview:subview];
zoomer.backgroundColor = zoomerColor;
[self.scroller addSubview:zoomer];
}
}
推薦答案
這是一個 iOS 錯誤.我創建了 UIScrollView
的以下子類,以記錄 y
隨著時間的推移發生了什么以及誰在推動它:
It's an iOS bug. I created the following subclass of UIScrollView
to get a log of what happens to y
over time and who was pushing it:
@implementation CSScrollView
- (void)setContentOffset:(CGPoint)contentOffset
{
NSLog(@"%0.0f %@", contentOffset.y, [NSThread callStackSymbols]);
NSLog(@"[%@]", self.layer.animationKeys);
[super setContentOffset:contentOffset];
}
@end
(并更改了故事板中的視圖類)
(and changed the view class in the storyboard)
當您松開手指時,名為 UIScrollView _smoothScrollDisplayLink:
的方法開始將滾動視圖動畫化到其最終位置.根據第二個日志,不涉及 CAAnimation
,滾動視圖使用自己的顯示鏈接進行自己的轉換.該自定義代碼似乎犯了從 y = 不管
到 y = 0
的動畫錯誤,沒有考慮到內容偏移.
When you release your finger, a method called UIScrollView _smoothScrollDisplayLink:
starts animating the scroll view to its final position. As per the second log, there's no CAAnimation
involved, the scroll view uses its own display link to do its own transition. That custom code appears to make the mistake of animating from y = whatever
to y = 0
, failing to take the content offset into account.
作為概念驗證黑客,我將代碼更改為:
As a proof-of-concept hack I changed the code to:
@implementation CSScrollView
- (void)setContentOffset:(CGPoint)contentOffset
{
contentOffset.y = -64.0f;
[super setContentOffset:contentOffset];
}
@end
不出所料,問題就消失了.
And, unsurprisingly, the problem went away.
您可能不想對 -64.0f
進行硬編碼,但我的結論是:
You probably don't want to hard code the -64.0f
but I'd conclude:
- 這是一個 iOS 錯誤;
- 通過
UIScrollView
的子類和- setContentOffset:
的適當自定義實現拒絕無意義的值來解決此問題.
- it's an iOS bug;
- work around it by rejecting nonsensical values via a subclass of
UIScrollView
with a suitable custom implementation of- setContentOffset:
.
一種合理的通用方法可能是檢查 self.panGestureRecognizer
的 state
- 這將允許您區分用戶負責的滾動和其他不負責的滾動依賴于任何未記錄的 API 或復雜的委托事件捕獲.然后,如有必要,從當前值中刪除正確的 contentOffset.y
而不是硬編碼.
A sensible generic means might be to check the state
of self.panGestureRecognizer
— that'll allow you to differentiate between scrolls the user is responsible for and other scrolls without relying on any undocumented API or complicated capturing of delegate events. Then if necessary crib the correct contentOffset.y
from the current value rather than hardcoding it.
這篇關于UIScrollView 上的邊界自動更改,帶有內容插圖的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!