問(wèn)題描述
我想要得到的是與此滾動(dòng)視圖相同的行為:
What I want to get is the same behaviour that this scroll view has:
我知道這是使用 HTML 而不是本機(jī) API,但我正在嘗試將其實(shí)現(xiàn)為 UIKit 組件.
I know that this is using HTML and not the native API, but I'm trying to implement it as a UIKit component.
現(xiàn)在,我正在尋找的行為:
- 請(qǐng)注意,這是一個(gè)分頁(yè)滾動(dòng)視圖,但頁(yè)面大小"小于視圖的寬度.
- 當(dāng)您從左到右滾動(dòng)時(shí),每個(gè)頁(yè)面都會(huì)捕捉"到最左邊的項(xiàng)目.
- 當(dāng)您從右端向左滾動(dòng)時(shí),它會(huì)捕捉"到最右邊的項(xiàng)目.
同一頁(yè),但現(xiàn)在從右到左:
The same page but now right-to-left:
我的嘗試:
- 我嘗試讓滾動(dòng)視圖小于它的超級(jí)視圖并覆蓋 hitTest,這讓我得到了從左到右的行為.
- 我已嘗試實(shí)現(xiàn) scrollViewWillEndDragging:withVelocity:targetContentOffset: 并設(shè)置我想要的 targetContentOffset,但由于我無(wú)法更改速度,它只會(huì)滾動(dòng)太慢或太快.
- 我嘗試實(shí)現(xiàn) scrollViewDidEndDecelerating: 然后動(dòng)畫到正確的偏移量,但滾動(dòng)視圖首先停止然后移動(dòng),它看起來(lái)不自然.
- 我嘗試實(shí)現(xiàn) scrollViewDidEndDragging:willDecelerate: 然后動(dòng)畫到正確的偏移量,但滾動(dòng)視圖跳躍"并且動(dòng)畫不正確.
我沒(méi)有想法.
謝謝!
更新:
我最終使用了 Rob Mayoff 的方法,它看起來(lái)很干凈.我對(duì)其進(jìn)行了更改,使其在速度為 0 時(shí)可以工作,例如當(dāng)用戶拖動(dòng)、停止和松開(kāi)手指時(shí).
I ended up using Rob Mayoff's method, it looks clean. I changed it so it would work when the velocity is 0, for example when a user drags, stops and releases the finger.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(CGPoint *)targetContentOffset {
CGFloat maxOffset = scrollView.contentSize.width - scrollView.bounds.size.width;
CGFloat minOffset = 0;
if (velocity.x == 0) {
CGFloat targetX = MAX(minOffset,MIN(maxOffset, targetContentOffset->x));
CGFloat diff = targetX - baseOffset;
if (ABS(diff) > offsetStep/2) {
if (diff > 0) {
//going left
baseOffset = MIN(maxOffset, baseOffset + offsetStep);
} else {
//going right
baseOffset = MAX(minOffset, baseOffset - offsetStep);
}
}
} else {
if (velocity.x > 0) {
baseOffset = MIN(maxOffset, baseOffset + offsetStep);
} else {
baseOffset = MAX(minOffset, baseOffset - offsetStep);
}
}
targetContentOffset->x = baseOffset;
}
此解決方案的唯一問(wèn)題是滑動(dòng)滾動(dòng)視圖不會(huì)產(chǎn)生反彈"效果.感覺(jué)卡住"了.
The only problem with this solution is that swiping the scroll view doesn't produce the "bounce" effect. It feels "stuck".
推薦答案
設(shè)置scrollView.decelerationRate = UIScrollViewDecelerationRateFast
,結(jié)合實(shí)現(xiàn)scrollViewWillEndDragging:withVelocity:targetContentOffset:
,好像使用集合視圖為我工作.
Setting scrollView.decelerationRate = UIScrollViewDecelerationRateFast
, combined with implementing scrollViewWillEndDragging:withVelocity:targetContentOffset:
, seems to work for me using a collection view.
首先,我給自己一些實(shí)例變量:
First, I give myself some instance variables:
@implementation ViewController {
NSString *cellClassName;
CGFloat baseOffset;
CGFloat offsetStep;
}
在viewDidLoad
中,我設(shè)置了視圖的decelerationRate
:
In viewDidLoad
, I set the view's decelerationRate
:
- (void)viewDidLoad {
[super viewDidLoad];
cellClassName = NSStringFromClass([MyCell class]);
[self.collectionView registerNib:[UINib nibWithNibName:cellClassName bundle:nil] forCellWithReuseIdentifier:cellClassName];
self.collectionView.decelerationRate = UIScrollViewDecelerationRateFast;
}
我需要 offsetStep
為適合視圖屏幕邊界的整數(shù)個(gè)項(xiàng)目的大小.我在 viewDidLayoutSubviews
中計(jì)算它:
I need offsetStep
to be the size of an integral number of items that fit in the view's on-screen bounds. I compute it in viewDidLayoutSubviews
:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
CGFloat stepUnit = layout.itemSize.width + layout.minimumLineSpacing;
offsetStep = stepUnit * floorf(self.collectionView.bounds.size.width / stepUnit);
}
我需要 baseOffset
在滾動(dòng)開(kāi)始之前成為視圖的 X 偏移量.我在 viewDidAppear:
:
I need baseOffset
to the be the X offset of the view before scrolling starts. I initialize it in viewDidAppear:
:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
baseOffset = self.collectionView.contentOffset.x;
}
然后我需要強(qiáng)制視圖以 offsetStep
的步長(zhǎng)滾動(dòng).我在 scrollViewWillEndDragging:withVelocity:targetContentOffset:
中執(zhí)行此操作.根據(jù) velocity
,我將 baseOffset
增加或減少 offsetStep
.但我將 baseOffset
鉗制為最小值 0 和最大值 contentSize.width - bounds.size.width
.
Then I need to force the view to scroll in steps of offsetStep
. I do that in scrollViewWillEndDragging:withVelocity:targetContentOffset:
. Depending on the velocity
, I increase or decrease baseOffset
by offsetStep
. But I clamp baseOffset
to a minimum of 0 and a maximum of the contentSize.width - bounds.size.width
.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
if (velocity.x < 0) {
baseOffset = MAX(0, baseOffset - offsetStep);
} else if (velocity.x > 0) {
baseOffset = MIN(scrollView.contentSize.width - scrollView.bounds.size.width, baseOffset + offsetStep);
}
targetContentOffset->x = baseOffset;
}
請(qǐng)注意,我不在乎 targetContentOffset->x
是什么.
Note that I don't care what targetContentOffset->x
comes in as.
這具有與最左側(cè)可見(jiàn)項(xiàng)的左邊緣對(duì)齊的效果,直到用戶一直滾動(dòng)到最后一項(xiàng).此時(shí)它與最右側(cè)可見(jiàn)項(xiàng)的右邊緣對(duì)齊,直到用戶一直滾動(dòng)到左側(cè).這似乎與 App Store 應(yīng)用的行為相符.
This has the effect of aligning to the left edge of the leftmost visible item, until the user scrolls all the way to the last item. At that point it aligns to the right edge of the rightmost visible item, until the user scroll all the way to the left. This seems to match the behavior of the App Store app.
如果這對(duì)您不起作用,您可以嘗試將最后一行 (targetContentOffset->x = baseOffset
) 替換為:
If that doesn't work for you, you can try replacing the last line (targetContentOffset->x = baseOffset
) with this:
dispatch_async(dispatch_get_main_queue(), ^{
[scrollView setContentOffset:CGPointMake(baseOffset, 0) animated:YES];
});
這也適用于我.
您可以在此 git 存儲(chǔ)庫(kù)中找到我的測(cè)試應(yīng)用 .
You can find my test app in this git repository.
這篇關(guān)于如何使 UIScrollView 與圖標(biāo)對(duì)齊(如 App Store:功能)的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!