实现婚礼纪类似的欢迎页
老规矩,上图(无图无真相),看官们可以先自行思考一下怎么实现才不显得代码臃肿,易于维护和调试,效果图奉上:
好的....
思考时间结束。
观察现象
如下:第二个imageView2
初始位置显示位置是在最中间的部分处于屏幕的边缘,scrollView
滚动一屏的宽是全部显示。
实现思路
如下:根据scrollView
的滚动的范围动态改变imageView
的位置。
这里会有一个思维误区:就是直接把imageView
直接加到scrollView
上,然后去改变imageView
在scrollView
上的布局,这样做你还要动态的改变scrollView
的contentSize
,并且你在使用pagingEnabled
属性时也会出现一些意料之外的问题;
要优雅的实现类似的交互效果,我们应当从面向对象的角度思考(oop),imageView
应该被封装出能够单独处理自己偏移的对象,scrollView
仅处理偏移量
的计算,不应该改变自身的contentSize
(类似于collectionView
和collectionCell
的处理逻辑);
项目代码传送门;
好了,接下来我们来一步步实现:
-
将
imageView
的需要做偏移的约束设置为DRContentView
的属性,并将勾选DRContentViwe
的Clip to Bounds
,控制偏移的约束如下图所示,leading
,trailing
- 在
DRContentView.h
里暴露一个修改偏移量的方法,并在.m
实现它;
#import <UIKit/UIKit.h>
@interface DRContentView : UIView
- (void)setImage:(UIImage *)image;
/*
* 修改偏移量
*/
- (void)changeOffset:(CGFloat)value;
@end
#import "DRContentView.h"
@interface DRContentView ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *trailingSpace;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leadingSpace;
@end
@implementation DRContentView
- (void)setImage:(UIImage *)image {
self.imageView.image = image;
}
- (void)changeOffset:(CGFloat)value {
self.leadingSpace.constant = -value;
self.trailingSpace.constant = value;
}
@end
5.回到ViewController.m
中,添加视图
#import "ViewController.h"
#import "DRContentView.h"
@interface ViewController ()<UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
if (@available(iOS 11.0, *)) {
self.scrollView.contentInsetAdjustmentBehavior = UIScrollViewDecelerationRateNormal;
} else {
self.automaticallyAdjustsScrollViewInsets = NO;
}
self.scrollView.delegate = self;
[self addSubviews];
}
- (void)addSubviews {
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
for (NSInteger i = 0; i < 4; i++) {
NSString *imageName = [NSString stringWithFormat:@"%@",@(i+1)];
UIImage *image = [UIImage imageNamed:imageName];
DRContentView *subview = [[[NSBundle mainBundle] loadNibNamed:@"DRContentView" owner:nil options:nil] lastObject];
subview.frame = CGRectMake(i * width, 0, width, height);
[subview setImage:image];
[self.scrollView addSubview:subview];
if (i == 0 || i == 3) {
continue;
}
[subview changeOffset:(width * 0.5)];
}
self.scrollView.contentSize = CGSizeMake(4 * width, height - 20);
self.scrollView.pagingEnabled = YES;
self.scrollView.bounces = NO;
}
#pragma mark --- UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
}
@end
6.cmd
+R
效果如下如下:
- 我们在
- scrollViewDidScroll:
防范重进行对应contentView
的偏移量计算; 注意:这里设置了UIScrollView
的showsVerticalScrollIndicator
和showsHorizontalScrollIndicator
方法为NO
(sb中取消勾选),否则你就要在区出DRContentView
时进行相应的判断了🙈
/*
计算公式:
初始偏移量 = (width * 0.5)
滑动偏移量 = (offsetX - width * index)
改变的值 = 初始偏移量 - 滑动偏移量
*/
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetX = scrollView.contentOffset.x;
CGFloat width = scrollView.bounds.size.width;
if (offsetX < width) {
//获取到第二个 item
DRContentView *item = scrollView.subviews[1];
[item changeOffset:(width * 0.5 - offsetX * 0.5)];
}else if (offsetX < width * 2) {
DRContentView *item2 = scrollView.subviews[1];
[item2 changeOffset:0];
//获取到第三个 item
DRContentView *item = scrollView.subviews[2];
[item changeOffset:(width * 0.5 - (offsetX - width) * 0.5)];
}else if (offsetX < width * 3 - 0.1) {
DRContentView *item3 = scrollView.subviews[2];
[item3 changeOffset:0];
//获取到第四个 item
DRContentView *item = scrollView.subviews[3];
[item changeOffset:(width * 0.5 - ((offsetX - 2 * width) * 0.5))];
}else if (offsetX >= width * 3 - 0.1) {
//获取到第四个 item
DRContentView *item = scrollView.subviews[3];
[item changeOffset:0];
}
}
对应的计算问题大家应该都能自己算出来,这里不做过多讨论了,至于其他需要补充的,还是看github源码吧,用到的图片就不单独贴出来