IOS实战 (1) 之 仿 LOFTER 底部 水平滑动(也有 Android 版本哦)

写在前面的话##

博主 一个懒技术, 工作两年多,做过一年多 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));// 否则正常

}

Android 效果图##

Android 效果图

关键!!!代码下载##

Android
代码下载链接
iOS iCarousel库实现
代码下载链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容