Ios UIScrollView自定义分页 我的问题与一种定制的分页方式有关,我试图用一个滚动程序来做,如果你首先考虑在一个老虎机中实现的滚动视图的类型,这是很容易可视化的。
假设我的UIScrollView的宽度为100像素。假设它包含3个内部视图,每个视图的宽度为30像素,这样它们之间的间隔宽度为3像素。我希望实现的分页类型是,每个页面都是我的一个视图(30像素),而不是滚动视图的整个宽度 我知道,通常情况下,如果视图占据了滚动视图的整个宽度,并且启用了分页,那么一切都正常。但是,在我的自定义分页中,我还希望滚动视图中的周围视图也可见Ios UIScrollView自定义分页 我的问题与一种定制的分页方式有关,我试图用一个滚动程序来做,如果你首先考虑在一个老虎机中实现的滚动视图的类型,这是很容易可视化的。,ios,iphone,objective-c,uiview,uiscrollview,Ios,Iphone,Objective C,Uiview,Uiscrollview,假设我的UIScrollView的宽度为100像素。假设它包含3个内部视图,每个视图的宽度为30像素,这样它们之间的间隔宽度为3像素。我希望实现的分页类型是,每个页面都是我的一个视图(30像素),而不是滚动视图的整个宽度 我知道,通常情况下,如果视图占据了滚动视图的整个宽度,并且启用了分页,那么一切都正常。但是,在我的自定义分页中,我还希望滚动视图中的周围视图也可见 我该怎么做呢?我只是为另一个项目做的。您需要做的是将UIScrollView放入UIView的自定义实现中。我为此创建了一个名为E
我该怎么做呢?我只是为另一个项目做的。您需要做的是将UIScrollView放入UIView的自定义实现中。我为此创建了一个名为ExtendedHitAreaViewController的类。ExtendedHitAreaView覆盖hitTest函数以返回其第一个子对象,即滚动视图 您的滚动视图应该是您想要的页面大小,即30像素,clipsToBounds=NO。 “扩展命中区域”视图应该是要显示的区域的完整大小,clipsToBounds=YES 将滚动视图作为子视图添加到扩展命中区域视图中,然后将扩展命中区域视图添加到viewcontroller的视图中
@implementation ExtendedHitAreaViewContainer
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self pointInside:point withEvent:event]) {
if ([[self subviews] count] > 0) {
//force return of first child, if exists
return [[self subviews] objectAtIndex:0];
} else {
return self;
}
}
return nil;
}
@end
自iOS 5以来,存在以下委托方法:
-(void)ScrollViewWillendDraging:(UIScrollView*)scrollView with velocity:(CGPoint)velocity targetContentOffset:(inout CGPoint*)targetContentOffset
所以你可以这样做:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint
*)targetContentOffset {
if (scrollView == self.scrollView) {
CGFloat x = targetContentOffset->x;
x = roundf(x / 30.0f) * 30.0f;
targetContentOffset->x = x;
}
}
对于更高的速度,如果您想要更活泼的感觉,您可能希望调整targetContentOffset,使其稍有不同 经过几天的研究和故障排除,我找到了适合我的东西 首先,您需要对scrollview所在的视图进行子类化,并使用以下内容覆盖此方法:
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event {
UIView* child = nil;
if ((child = [super hitTest:point withEvent:event]) == self)
return (UIView *)_calloutCell;
return child;
}
然后,scrollview委托方法中发生了所有神奇的事情
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
//_lastOffset is declared in the header file
//@property (nonatomic) CGPoint lastOffset;
_lastOffset = scrollView.contentOffset;
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
CGPoint currentOffset = scrollView.contentOffset;
CGPoint newOffset = CGPointZero;
if (_lastOffset.x < currentOffset.x) {
// right to left
newOffset.x = _lastOffset.x + 298;
}
else {
// left to right
newOffset.x = _lastOffset.x - 298;
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelay:0.0f];
targetContentOffset->x = newOffset.x;
[UIView commitAnimations];
}
alcides的解决方案非常有效。只要输入ScrollViewDiEndDraging和ScrollViewWilEndDraging,我就启用/禁用scrollview的滚动。如果用户在分页动画完成之前滚动几次,则单元格会稍微不对齐 因此,我:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
scrollView.scrollEnabled = NO
CGPoint currentOffset = scrollView.contentOffset;
CGPoint newOffset = CGPointZero;
if (_lastOffset.x < currentOffset.x) {
// right to left
newOffset.x = _lastOffset.x + 298;
}
else {
// left to right
newOffset.x = _lastOffset.x - 298;
}
[UIView animateWithDuration:0.4 animations:^{
targetContentOffset.x = newOffset.x
}];
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView {
scrollView.scrollEnabled = YES
}
-(void)ScrollViewWillendDraging:(UIScrollView*)带速度的scrollView:(CGPoint)速度targetContentOffset:(inout CGPoint*)targetContentOffset{
scrollView.scrollEnabled=否
CGPoint currentOffset=scrollView.contentOffset;
CGPoint newOffset=CGPointZero;
如果(_lastOffset.x
我也有同样的问题,在iOS 8上测试后,这对我来说非常有效
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset
{
NSInteger index = lrint(targetContentOffset->x/_pageWidth);
NSInteger currentPage = lrint(scrollView.contentOffset.x/_pageWidth);
if(index == currentPage) {
if(velocity.x > 0)
index++;
else if(velocity.x < 0)
index--;
}
targetContentOffset->x = index * _pageWidth;
}
-(void)ScrollViewWillendDraging:(UIScrollView*)scrollView
withVelocity:(CGPoint)速度
targetContentOffset:(输入输出CGPoint*)targetContentOffset
{
NSInteger index=lrint(targetContentOffset->x/_pageWidth);
NSInteger currentPage=lrint(scrollView.contentOffset.x/_pageWidth);
如果(索引==currentPage){
如果(速度x>0)
索引++;
否则如果(速度x<0)
索引--;
}
targetContentOffset->x=索引*\u页面宽度;
}
我必须检查速度,如果速度不为零,则总是转到下一页/上一页,否则在进行非常短和快速的滑动时,它会给出非动画跳跃
更新:这似乎效果更好:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset
{
CGFloat index = targetContentOffset->x/channelScrollWidth;
if(velocity.x > 0)
index = ceil(index);
else if(velocity.x < 0)
index = floor(index);
else
index = round(index);
targetContentOffset->x = index * channelScrollWidth;
}
-(void)ScrollViewWillendDraging:(UIScrollView*)scrollView
withVelocity:(CGPoint)速度
targetContentOffset:(输入输出CGPoint*)targetContentOffset
{
CGFloat index=targetContentOffset->x/通道滚动宽度;
如果(速度x>0)
指数=ceil(指数);
否则如果(速度x<0)
指数=楼层(指数);
其他的
指数=圆形(指数);
targetContentOffset->x=索引*通道宽度;
}
对于水平滚动视图,请使用
y
而不是x
来显示垂直滚动视图。我在滚动视图中有许多不同的视图,带有按钮和手势识别器
@picciano的答案对我来说不起作用(滚动效果很好,但按钮和识别器无法触摸),因此我找到了这个解决方案:
class ExtendedHitAreaView : UIScrollView {
// Your insets
var hitAreaEdgeInset = UIEdgeInsets(top: 0, left: -20, bottom: 0, right: -20)
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
let hitBounds = UIEdgeInsetsInsetRect(bounds, hitAreaEdgeInset)
return CGRectContainsPoint(hitBounds, point)
}
}
我一直在努力克服这个问题,我发现了一个几乎完美的解决方案,它可以满足您的需要,并且可以使用您想要的页面宽度 我从UIScrollView中将scrollView.isPaging设置为false(同时,默认为false),并将其委托设置为UIScrollViewDelegate
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// Stop scrollView sliding:
targetContentOffset.pointee = scrollView.contentOffset
if scrollView == scrollView {
let maxIndex = slides.count - 1
let targetX: CGFloat = scrollView.contentOffset.x + velocity.x * 60.0
var targetIndex = Int(round(Double(targetX / (pageWidth + spacingWidth))))
var additionalWidth: CGFloat = 0
var isOverScrolled = false
if targetIndex <= 0 {
targetIndex = 0
} else {
// in case you want to make page to center of View
// by substract width with this additionalWidth
additionalWidth = 20
}
if targetIndex > maxIndex {
targetIndex = maxIndex
isOverScrolled = true
}
let velocityX = velocity.x
var newOffset = CGPoint(x: (CGFloat(targetIndex) * (self.pageWidth + self.spacingWidth)) - additionalWidth, y: 0)
if velocityX == 0 {
// when velocityX is 0, the jumping animation will occured
// if we don't set targetContentOffset.pointee to new offset
if !isOverScrolled && targetIndex == maxIndex {
newOffset.x = scrollView.contentSize.width - scrollView.frame.width
}
targetContentOffset.pointee = newOffset
}
// Damping equal 1 => no oscillations => decay animation:
UIView.animate(
withDuration: 0.3, delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: velocityX,
options: .allowUserInteraction,
animations: {
scrollView.contentOffset = newOffset
scrollView.layoutIfNeeded()
}, completion: nil)
}
}
func-scrollViewWillendDraging(scrollView:UIScrollView,withVelocity:CGPoint,targetContentOffset:UnsafemeutablePointer){
//停止滚动视图滑动:
targetContentOffset.pointee=scrollView.contentOffset
如果scrollView==scrollView{
设maxIndex=slides.count-1
让targetX:CGFloat=scrollView.contentOffset.x+velocity.x*60.0
var targetIndex=Int(圆形(双精度)(targetX/(页面宽度+间距宽度)))
var附加宽度:CGFloat=0
var isOverScrolled=false
如果targetIndex maxIndex{
targetIndex=maxIndex
isOverScrolled=true
}
设velocityX=速度.x
var newOffset=CGPoint(x:(CGFloat(targetIndex)*(self.pageWidth+self.spacingWidth))-additionalWidth,y:0)
如果velocityX==0{
//当velocityX为
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// Stop scrollView sliding:
targetContentOffset.pointee = scrollView.contentOffset
if scrollView == scrollView {
let maxIndex = slides.count - 1
let targetX: CGFloat = scrollView.contentOffset.x + velocity.x * 60.0
var targetIndex = Int(round(Double(targetX / (pageWidth + spacingWidth))))
var additionalWidth: CGFloat = 0
var isOverScrolled = false
if targetIndex <= 0 {
targetIndex = 0
} else {
// in case you want to make page to center of View
// by substract width with this additionalWidth
additionalWidth = 20
}
if targetIndex > maxIndex {
targetIndex = maxIndex
isOverScrolled = true
}
let velocityX = velocity.x
var newOffset = CGPoint(x: (CGFloat(targetIndex) * (self.pageWidth + self.spacingWidth)) - additionalWidth, y: 0)
if velocityX == 0 {
// when velocityX is 0, the jumping animation will occured
// if we don't set targetContentOffset.pointee to new offset
if !isOverScrolled && targetIndex == maxIndex {
newOffset.x = scrollView.contentSize.width - scrollView.frame.width
}
targetContentOffset.pointee = newOffset
}
// Damping equal 1 => no oscillations => decay animation:
UIView.animate(
withDuration: 0.3, delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: velocityX,
options: .allowUserInteraction,
animations: {
scrollView.contentOffset = newOffset
scrollView.layoutIfNeeded()
}, completion: nil)
}
}