写在前面的话
博主 一个懒技术, 毕业两年,做过大半年 Android,然后转 IOS, 虽然也做了不少小项目.但是一直 没有太多文档 博客的积累.现在希望 每隔一段时间就把项目用到的一些实用代码片段,与小的例子 与大家分享交流.就这…. over!!
- 先看看需要实现的效果图
- 再看看我们高仿的效果图
- 实现思路(引用了 github iCarousel 库 )
- 部分代码说明
- 代码下载链接
Lofter 效果图
效果 类似图片轮播. 当滑动时 两边视图有缩放的动画效果.
实现后的效果图
实现思路
一.整理功能特点,选择合适的方法去实现
(1)功能1: 每次滑动都会有一个 View 居中显示
(2)功能2:滑动有两边缩放的动画效果
(3)不同的 View 有各自的 点击事件.
经过分析 有两种实现方法.
第一种:是 UICollectionView 和 自定义 Layout
第二种就是 github 中大神 制作的高级零件.iCarousel.项目中为了 稳定性和效果性 使用的第三方的库.
但是自主思考 过程不能缺少.
先来分析一下 UICollectionView 的实现
关键在 自定义的UICollectionViewFlowLayout.API 的一些详解 参考
http://blog.csdn.net/qpwyj/article/details/51338337
动画缩放关键代码
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
CGFloat contentOffsetX = self.collectionView.contentOffset.x;
CGFloat collectionViewCenterX = self.collectionView.frame.size.width * 0.5;
//1.取出默认的cell的UICollectionViewLayoutAttributes
NSArray *attrs = [super layoutAttributesForElementsInRect:rect];
//2.遍历所有的布局属性
for (UICollectionViewLayoutAttributes *attr in attrs) {
CGFloat scale = 1 - fabs(attr.center.x - contentOffsetX - collectionViewCenterX) / self.collectionView.bounds.size.width;
//计算缩放比例.太小比例 不修改
if (scale< 0.7) {
attr.transform = CGAffineTransformMakeScale(0.7, 0.7);
}
}
return attrs;
}
滑动停止后 View 居中显示
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
CGRect lastRect;
lastRect.origin = proposedContentOffset;
lastRect.size = self.collectionView.frame.size;
//计算屏幕最中间的x
CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width*0.5;
//2.取出这个范围内的所有属性
NSArray *array = [self layoutAttributesForElementsInRect:lastRect];
//3.遍历所有属性
CGFloat adjustOffsetX = MAXFLOAT;
for (UICollectionViewLayoutAttributes *attr in array) {
if(ABS(attr.center.x - centerX) < ABS(adjustOffsetX)){
adjustOffsetX = attr.center.x - centerX;
}
}
return CGPointMake(proposedContentOffset.x+adjustOffsetX, proposedContentOffset.y);
}
此例子效果图
在实战项目中 本博主秉承 能搬砖就搬砖的思路. 开启了 github 的搬砖之旅
用 pod 或者下载代码 将第三方库(iCarousel)引入
不会使用 pods 工具的参考 http://blog.csdn.net/lilinoscar/article/details/46930387
准备工作: 创建新项目. 并有iCarousel库. 在 ViewController 中 导入iCarousel. h 头文件.
在 Xib 中创建 一个 View 把 Class 改为iCarousel. ( 可以代码中 创建). 实现. iCarouselDataSource, iCarouselDelegate.的部分方法
- (NSInteger)numberOfItemsInCarousel:(__unused iCarousel *)carousel
{
return _dataList.count;
}
- (UIView *)carousel:(__unused iCarousel *)carousel viewForItemAtIndex:(NSInteger)index reusingView:(UIView *)view
{
MyCardView *cardView = nil;
if (view == nil)
{
cardView= [[MyCardView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth*0.7, ScreenHeight*0.40)];
cardView.delegate=self;
view=cardView;
view.contentMode = UIViewContentModeCenter;
}
NSDictionary *dic=_dataList[index];
[cardView setData:dic];
return cardView;
}
- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value
{
//customize carousel display
switch (option)
{
case iCarouselOptionWrap:
{
//normally you would hard-code this to YES or NO
return YES;
}
case iCarouselOptionSpacing:
{
//add a bit of spacing between the item views
return value * 1.1f;
}
case iCarouselOptionFadeMax:
case iCarouselOptionShowBackfaces:
case iCarouselOptionRadius:
case iCarouselOptionAngle:
case iCarouselOptionArc:
case iCarouselOptionTilt:
case iCarouselOptionCount:
case iCarouselOptionFadeMin:
case iCarouselOptionFadeMinAlpha:
case iCarouselOptionFadeRange:
case iCarouselOptionOffsetMultiplier:
case iCarouselOptionVisibleItems:
{
return value;
}
}
}
- (CATransform3D)carousel:(iCarousel *)carousel itemTransformForOffset:(CGFloat)offset baseTransform:(CATransform3D)transform
{
static CGFloat max_sacle = 1.0f;
static CGFloat min_scale = 0.8f;
if (offset <= 1 && offset >= -1){
float tempScale = offset < 0 ? 1 + offset : 1 - offset;
float slope = (max_sacle-min_scale) / 1;
CGFloat scale = min_scale+slope*tempScale;
transform = CATransform3DScale(transform, scale, scale, 1);
}else{
transform = CATransform3DScale(transform, min_scale, min_scale, 1);
}
return CATransform3DTranslate(transform, offset * self.myICarousel.itemWidth * 1.2, 0.0, 0.0);
}
-(void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index{
}
-(void)itemClickIndex:(NSInteger)index{
NSLog(@"被点击的 是 第%ld 卡片中的 第 %ld",(long)_iCarouselindex+1,(long)index+1);
}
其中 (UIView )carousel:(__unused iCarousel )carousel viewForItemAtIndex:(NSInteger)index reusingView:(UIView *)view 方法 返回的每个 卡片的 View 可以自定义. Demo 中 随意编写的,读者可以重新编写,提高代码的重用性.
IOS 最终效果图
Android 版本 使用的deprecation的类 Gallery.虽然不建议使用了.很老的 API 但是做这个效果是我能想到最简单的一个.如果有 新的实现方法可以跟我讲一下.(没有找到合适的 类库)
核心代码 就是 View 缩放一下.
if (selectNum == position) {
holder.mainLinlayout.setLayoutParams(new Gallery.LayoutParams(gallery.getLayoutParams().height - 100, gallery.getLayoutParams().height));// 如果被选择则放大显示
} else {
holder.mainLinlayout.setLayoutParams(new Gallery.LayoutParams((gallery.getLayoutParams().height - 100) / 10 * 9,
gallery.getLayoutParams().height / 10 * 9));// 否则正常
}