ios - Página de UIScrollView personalizada con scrollViewWillEndDragging
uikit uiscrollviewdelegate (5)
Pude realizar una prueba rápida y obtuve esto para disparar correctamente y hacer que mi objeto se detuviera según lo deseado. Hice esto usando la siguiente prueba simple:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
targetContentOffset->x = scrollView.contentOffset.x - 10;
}
Parece que este método probablemente no sea el problema en su código, pero es más probable que su ''goodOffsetX'' no esté calculando correctamente un valor válido para detenerse.
Estoy tratando de usar el nuevo scrollViewWillEndDragging: withVelocity: targetContentOffset: llamada de delegado de UIScrollView en iOS 5, pero parece que no logro que me responda correctamente. Estoy cambiando el valor de targetContentOffset-> x pero nunca termina siendo usado. Sé que el código se está ejecutando porque llegará a los puntos de interrupción en esa función. Incluso he intentado establecer el valor de compensación en un número codificado para que yo sepa dónde terminaría pero nunca funciona.
¿Alguien ha podido usar esto correctamente y hacerlo funcionar? ¿Hay alguna otra llamada de delegado que deba implementarse para que esto funcione?
Aquí está mi código en caso de que alguien vea algo malo con él:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
// goodOffsetX returns the contentOffset i want the scrollView to stop at
CGFloat goodOffsetX = [self _horizontalContentOffsetForTargetHorizontalContentOffset:(*targetContentOffset).x velocity:velocity.x];
NSLog( @" " );
NSLog( @"scrollViewWillEndDragging" );
NSLog( @" velocity: %f", velocity.x );
NSLog( @" currentX: %f", scrollView.contentOffset.x );
NSLog( @" uikit targetX: %f", (*targetContentOffset).x );
NSLog( @" pagedX: %f", goodOffsetX );
targetContentOffset->x = goodOffsetX;
}
Puede implementar la paginación personalizada con este código:
- (float) pageWidth {
return ((UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout).itemSize.width +
((UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout).minimumInteritemSpacing;
}
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {
CGFloat pageWidth = self.collectionView.frame.size.width + 10 /* Optional Photo app like gap between images. Or use [self pageWidth] in case if you want the next page be also visible */;
_currentPage = floor((self.collectionView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
NSLog(@"Dragging - You are now on page %i", _currentPage);
}
- (void) scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint*)targetContentOffset {
CGFloat pageWidth = self.collectionView.frame.size.width + 10; // [self pageWidth]
int newPage = _currentPage;
if (velocity.x == 0) { // slow dragging not lifting finger
newPage = floor((targetContentOffset->x - pageWidth / 2) / pageWidth) + 1;
}
else {
newPage = velocity.x > 0 ? _currentPage + 1 : _currentPage - 1;
if (newPage < 0)
newPage = 0;
if (newPage > self.collectionView.contentSize.width / pageWidth)
newPage = ceil(self.collectionView.contentSize.width / pageWidth) - 1.0;
}
NSLog(@"Dragging - You will be on %i page (from page %i)", newPage, _currentPage);
*targetContentOffset = CGPointMake(newPage * pageWidth, targetContentOffset->y);
}
Por supuesto que debe establecer pagingEnabled = NO. _currentPage es una clase iVar. Gracias a http://www.mysamplecode.com/2012/12/ios-scrollview-example-with-paging.html por señalar el camino correcto.
Swift 2.2:
extension SomeCollectionViewController {
override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
let pageWidth = Float(collectionView!.frame.size.width)
let xCurrentOffset = Float(collectionView!.contentOffset.x)
currentPage = floor((xCurrentOffset - pageWidth / 2) / pageWidth) + 1
}
override func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let pageWidth = Float(collectionView!.frame.size.width)
let targetXContentOffset = Float(targetContentOffset.memory.x)
let contentWidth = Float(collectionView!.contentSize.width)
var newPage = currentPage
if velocity.x == 0 {
newPage = floor((targetXContentOffset - pageWidth / 2) / pageWidth) + 1
} else {
newPage = velocity.x > 0 ? currentPage + 1 : currentPage - 1
if newPage < 0 {
newPage = 0
}
if newPage > contentWidth / pageWidth {
newPage = ceil(contentWidth / pageWidth) - 1.0
}
}
targetContentOffset.memory.x = CGFloat(newPage * pageWidth)
}
}
También utilicé collectionView?.decelerationRate = UIScrollViewDecelerationRateFast
como lo sugiere @skagedal para mejorar la velocidad de la página.
SWIFT 3
Con una demostración aquí https://github.com/damienromito/CollectionViewCustom
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let pageWidth = Float(itemWidth + itemSpacing)
let targetXContentOffset = Float(targetContentOffset.pointee.x)
let contentWidth = Float(collectionView!.contentSize.width )
var newPage = Float(self.pageControl.currentPage)
if velocity.x == 0 {
newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0
} else {
newPage = Float(velocity.x > 0 ? self.pageControl.currentPage + 1 : self.pageControl.currentPage - 1)
if newPage < 0 {
newPage = 0
}
if (newPage > contentWidth / pageWidth) {
newPage = ceil(contentWidth / pageWidth) - 1.0
}
}
let point = CGPoint (x: CGFloat(newPage * pageWidth), y: targetContentOffset.pointee.y)
targetContentOffset.pointee = point
}
public func scrollViewWillEndDragging(_ scrollView: UIScrollView ,withVelocity velocity: CGPoint, targetContentOffset:
UnsafeMutablePointer<CGPoint>){
let pageWidth = Float(appWidth + itemSpacing)
let targetXContentOffset = Float(targetContentOffset.pointee.x)
var newPage = Float(currentPageIndex)
// I use this way calculate newPage:
newPage = roundf(targetXContentOffset / pageWidth);
//if velocity.x == 0 {
// newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0
//} else {
// newPage = Float(velocity.x > 0 ? newPage + 1 : newPage - 1)
// if newPage < 0 {
// newPage = 0
// }
// if (newPage > contentWidth / pageWidth) {
// newPage = ceil(contentWidth / pageWidth) - 1.0
// }
//}
let targetOffsetX = CGFloat(newPage * pageWidth)
let point = CGPoint (x: targetOffsetX, y: targetContentOffset.pointee.y)
targetContentOffset.pointee = point
}