iOS 网易新闻首页进化版Demo(MXSegmentedPager),自带平行头部拉伸

网易新闻首页类似的界面简直太常见了,需求不同自然做出来的效果不同了,之前

用ScrollView写过一个控制器的封装,但是这里根本没有考虑到控制器的复用以及预加

载机制,如果没考虑复用的话当界面爆炸的时候估计你的App会很卡,例如半塘这样

的,我抓包发现貌似会预加载当前界面后三个界面,让用户滑动的时候能第一时间看到

数据,这样的机制蛮不错的,今天来介绍个能复用的框架,顺带介绍个另一个高斯模糊

的Catagory。

上图

这里的三个界面分别是最普通的控制器,webview以及双TableView

该框架有两种用法,第一种直接创建一个ViewController继承它,第二个就是在控制器写成属性

这里我们介绍第二种

@property (nonatomic,strong)MXSegmentedPager
*segmentedPager;//!< MX框架

第一步(创建和准备)

用你的终端创建podfile文件,在里面写上你需要的库,然后就开搞了

platform:ios,‘7.0‘

target‘imageBlur‘
do

pod‘MXSegmentedPager‘

pod‘SDWebImage‘

pod‘Masonry‘

end

既然准备的话就准备一个可以拉伸的头部,来展示拉伸效果以及高斯模糊的效果

属性拖出来以备后续操作

第二步(初始化框架MX)

我们展示三个控制器,按如下,分别给出几个属性

超级无敌详细的备注介绍如何初始化框架

// 初始化MX框架控制器,头部和选择栏
- (void)initMX
{
    // 头部
    self.segmentedPager = [[MXSegmentedPager alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
    self.segmentedPager.parallaxHeader.view = self.headView; // 注意这里加载平行头部
    // MXParallaxHeaderModeCenter MXParallaxHeaderModeCenter MXParallaxHeaderModeTop  MXParallaxHeaderModeBottom四个,大家可以自己测试
    self.segmentedPager.parallaxHeader.mode = MXParallaxHeaderModeFill; // 平行头部填充模式
    self.segmentedPager.parallaxHeader.height = 240; // 头部高度
    self.segmentedPager.parallaxHeader.minimumHeight = 64; // 头部最小高度

    // 选择栏控制器属性
    self.segmentedPager.segmentedControl.borderWidth = 1.0; // 边框宽度
    self.segmentedPager.segmentedControl.borderColor = [UIColor redColor]; // 边框颜色
    self.segmentedPager.segmentedControl.frame = CGRectMake(0, 0, self.view.bounds.size.width, 44); // frame
    self.segmentedPager.segmentedControl.segmentEdgeInset = UIEdgeInsetsMake(0, 10, 0, 10);// 间距
    self.segmentedPager.segmentedControl.selectionIndicatorHeight = 0;// 底部是否需要横条指示器,0的话就没有了,如图所示
    // 底部指示器的宽度是否根据内容
    self.segmentedPager.segmentedControl.selectionStyle = HMSegmentedControlSelectionStyleTextWidthStripe;
    //HMSegmentedControlSelectionIndicatorLocationNone 不需要底部滑动指示器
    self.segmentedPager.segmentedControl.selectionIndicatorLocation = HMSegmentedControlSelectionIndicatorLocationNone;
    self.segmentedPager.segmentedControl.verticalDividerEnabled = NO;// 不可以垂直滚动
    // fix的枚举说明宽度是适应屏幕的,不会根据字体   HMSegmentedControlSegmentWidthStyleDynamic则是字体多大就多宽
    self.segmentedPager.segmentedControl.segmentWidthStyle = HMSegmentedControlSegmentWidthStyleFixed;

    // 默认状态的字体
    self.segmentedPager.segmentedControl.titleTextAttributes =
                            @{NSForegroundColorAttributeName : [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1],
                                         NSFontAttributeName : [UIFont systemFontOfSize:14]};
    // 选择状态下的字体
    self.segmentedPager.segmentedControl.selectedTitleTextAttributes =
                                    @{NSForegroundColorAttributeName : [UIColor colorWithRed:255/255.0 green:174/255.0 blue:1 alpha:1],
                                                 NSFontAttributeName : [UIFont systemFontOfSize:18]};
    self.segmentedPager.segmentedControlEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);

    self.segmentedPager.delegate = self;
    self.segmentedPager.dataSource = self;
    [self.view addSubview:self.segmentedPager];
    [self.segmentedPager mas_makeConstraints:^(MASConstraintMaker *make)
     {
         make.top.equalTo(self.view.mas_top).with.offset(0);
         make.left.equalTo(self.view.mas_left);
         make.bottom.equalTo(self.view.mas_bottom);
         make.right.equalTo(self.view.mas_right);
         make.width.equalTo(self.view.mas_width);
     }];
}

第三步(代理方法)

最关键的代理方法实现,分别是头部选择栏的代理数组以及控制器的数组View,具体的控制器初始化可以在懒加载中

实现

#pragma -mark <MXSegmentedPagerDelegate>

- (CGFloat)heightForSegmentedControlInSegmentedPager:(MXSegmentedPager *)segmentedPager
{
    // 指示栏的高度
    return 44.0f;
}

#pragma -mark <MXSegmentedPagerDataSource>

- (NSInteger)numberOfPagesInSegmentedPager:(MXSegmentedPager *)segmentedPager
{
    // 需要多少个界面
    return 3;
}

- (NSString *)segmentedPager:(MXSegmentedPager *)segmentedPager titleForSectionAtIndex:(NSInteger)index
{
    // 指示栏的文字数组
    return [@[@"控制器界面", @"WKWebView",@"双TableView"] objectAtIndex:index];
}

- (UIView *)segmentedPager:(MXSegmentedPager *)segmentedPager viewForPageAtIndex:(NSInteger)index
{
    // 第一个是控制器的View 第二个是WebView  第三个是自定义的View 这个也是最关键的,通过懒加载把对应控制的初始化View加载到框架上面去
    return [@[self.firstChildVC.view, self.webView, self.customView] objectAtIndex:index];
}

第四步(导航栏消失)

我们在滚动的时候需要让导航栏也跟着变换,那么还有个代理方法需要实现

// 滚动整体的时候调用
- (void)segmentedPager:(MXSegmentedPager *)segmentedPager didScrollWithParallaxHeader:(MXParallaxHeader *)parallaxHeader
{
    // 通过拿到滚动的对应的View
    UIScrollView *scrollView = (UIScrollView *)segmentedPager.subviews[0];
    NSLog(@"%lf",scrollView.contentOffset.y);
    // 计算alpha值
    CGFloat headAlpha = (1 - (-(scrollView.contentOffset.y + 64) / 136)) >= 0 ? (1 - (-(scrollView.contentOffset.y + 64) / 136)) : 0;
    self.headView.alpha = 1 - headAlpha;
    if (self.headView.alpha == 0)
    {
        self.navigationController.navigationBar.hidden = NO;
    }
    else
    {
        self.navigationController.navigationBar.hidden = YES;
    }
}

第五步(头部图片拉伸以及高斯模糊)

其实上面四个做完基本就差不多了,一个Demo就很简单的了,那么我们再加个头部,拉伸玩玩,自带的平行头部,

不玩白不玩

// 加载头部模糊视图的图片和头像
- (void)initHeadView
{
    // 圆形头像无需模糊
    self.nickImageView.layer.cornerRadius = 25.0f;
    self.nickImageView.clipsToBounds = YES;
    self.nickImageView.layer.borderColor = [[UIColor whiteColor] CGColor];
    self.nickImageView.layer.borderWidth = 2.0f;
    __weak typeof(self)weakSelf = self;
    [self.nickImageView sd_setImageWithURL:[NSURL URLWithString:@"http://twt.img.iwala.net/touxiang/563846208921b.jpg"]
                          placeholderImage:nil
                                 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
        if (image && cacheType == SDImageCacheTypeNone) {
            [weakSelf.nickImageView setNeedsDisplay];
            weakSelf.nickImageView.alpha = 0;
            [UIView animateWithDuration:1.0 animations:^{

                weakSelf.nickImageView.alpha = 1.0f;
            }];
        }
        else
        {
            weakSelf.nickImageView.alpha = 1.0f;
        }
    }];

    // 背景做成模糊,方法已经在Demo里面了,大家可以下载去取,一个方法暴露,简单就能实现
    [self.blurImageView sd_setImageWithURL:[NSURL URLWithString:@"http://twt.img.iwala.net/touxiang/563846208921b.jpg"]
                          placeholderImage:nil
                                 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
       [self.blurImageView setNeedsDisplay];

        // 模糊开始
        NSData *imageData = UIImageJPEGRepresentation(image, 0.5);
        // 模糊接口,参数越接近1越模糊,直接调用他就OK了
        UIImage *blurImage = [[UIImage imageWithData:imageData] blurredImage:0.15f];

        weakSelf.blurImageView.image = blurImage;
        if (image && cacheType == SDImageCacheTypeNone) {
            weakSelf.blurImageView.alpha = 0;
            [UIView animateWithDuration:1.0 animations:^{

                weakSelf.blurImageView.alpha = 1.0f;

            }];
        }
        else
        {
            weakSelf.blurImageView.alpha = 1.0f;
        }

    }];
    [self.headView layoutSubviews];
}

高斯的内部方法,可以拿去直接用

- (UIImage*)blurredImage:(CGFloat)blurAmount
{
    if (blurAmount < 0.0 || blurAmount > 1.0) {
        blurAmount = 0.5;
    }

    int boxSize = (int)(blurAmount * 40);
    boxSize = boxSize - (boxSize % 2) + 1;

    CGImageRef img = self.CGImage;

    vImage_Buffer inBuffer, outBuffer;
    vImage_Error error;

    void *pixelBuffer;

    CGDataProviderRef inProvider = CGImageGetDataProvider(img);
    CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);

    inBuffer.width = CGImageGetWidth(img);
    inBuffer.height = CGImageGetHeight(img);
    inBuffer.rowBytes = CGImageGetBytesPerRow(img);

    inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);

    pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));

    outBuffer.data = pixelBuffer;
    outBuffer.width = CGImageGetWidth(img);
    outBuffer.height = CGImageGetHeight(img);
    outBuffer.rowBytes = CGImageGetBytesPerRow(img);

    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);

    if (!error) {
        error = vImageBoxConvolve_ARGB8888(&outBuffer, &inBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    }

    if (error) {
#ifdef DEBUG
        NSLog(@"%s error: %zd", __PRETTY_FUNCTION__, error);
#endif

        return self;
    }

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    CGContextRef ctx = CGBitmapContextCreate(outBuffer.data,
                                             outBuffer.width,
                                             outBuffer.height,
                                             8,
                                             outBuffer.rowBytes,
                                             colorSpace,
                                             (CGBitmapInfo)kCGImageAlphaNoneSkipLast);

    CGImageRef imageRef = CGBitmapContextCreateImage (ctx);

    UIImage *returnImage = [UIImage imageWithCGImage:imageRef];

    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);

    free(pixelBuffer);
    CFRelease(inBitmapData);

    CGImageRelease(imageRef);

    return returnImage;
}

用法就介绍到这里,非常简单,和TableView的用法差不多,初始化之后直接实现几个

代理方法一样,用起来十分习惯,至于内部的复用是如何实现的这

里就不多介绍了,各位有兴趣的话可以看下源码是如何进行复用的

我去,忘了介绍了。这里还有个双TableView的展示

我们首先要做的是自定义一个View继承UIView

@interface MXCustomView () <MXPageProtocol, UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *table1;
@property (nonatomic, strong) UITableView *table2;
@end

两个TableView的初始化以及代理方法就不展开了,可以看到Demo,主要介绍个方法,让TableView是否能跟着整体

滚动与否

#pragma mark <MXPageProtocol>
- (BOOL)segmentedPager:(MXSegmentedPager *)segmentedPager shouldScrollWithView:(UIView *)view {
    // 返回NO就是代表是独立的
    if (view == self.table2) {
        return NO;
    }
    // YES就是整体的
    return YES;
}

很好玩的东西竟然差点忘了

Demo地址:https://github.com/DeftMKJ/blur

OVER~~~~~~

时间: 2024-10-12 00:15:21

iOS 网易新闻首页进化版Demo(MXSegmentedPager),自带平行头部拉伸的相关文章

网易新闻首页iOS

// //  ViewController.m //  wyy // //  Copyright © 2016年 zm. All rights reserved. // #import "ViewController.h" #import "ZMViewController.h" #import "ZMLabel.h" @interface ViewController ()<UIScrollViewDelegate> @proper

iOS实现网易新闻首页

主要就是这个页面,实现的主要功能有:1.点击上面的标题栏,下方的红色滚动条跟着到所点击的标题的下方;2中间的图片进行循环自动播放;3,点击下面的各项标签将所点击的标签添加到上面的标题栏,4当点击下面的标签在上面已经存在的时候将其从上面的标题栏移除 //viewDidLoad里面调用各种方法 - (void)viewDidLoad { // Do any additional setup after loading the view. self.titleArray = [NSMutableArr

iOS 网易新闻用到的框架

网易新闻iOS版在开发过程中曾经使用过的第三方开源类库.组件 1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功能强大, 现在许多人都用它取代 ASIHTTPRequest 2.Apple Reachability 网络监测,可以参考下这篇文章iOS网络监测如何区分2.3.4G? 3.DOUAudioStreamer 豆瓣的开源软件,DOUAudioStreamer

IOS 类似于网易新闻首页新闻轮播的组件

一.需求分析 1.可横向循环滚动新闻图片 2.滚动到对应图片时显示新闻标题 3.每张新闻图片可点击 4.有pageControl提示 5.具有控件的扩展能力 二.设计实现 1.显示图片使用SDWebImage第三方库,可缓存图片.通过url异步加载图片 2.使用一个横向滚动的UITableView实现循环滚动 3.使用一个黑色半透明的背景.白色文字的UILabel显示标题 4.定义每个新闻的数据结构: /** @brief 默认使用本地地址,如果本地没有的话,使用网络图片 */ @interfa

网易新闻首页骨架(父子控制器实现)

一:父子控制器的应用:效果如图: 二:代码 1 #import "RHMainViewController.h" 2 #import "RHNewsTableViewController.h" 3 #import "RHLable.h" 4 static const CGFloat lableCount = 8; 5 static const CGFloat lableWidth = 80; 6 static const CGFloat labl

android 仿网易新闻首页框架

   首页布局: 1 SliddingMenu  +  ViewPagerIndicator 2 JSON 解析   FastJson 3 网络请求  Volley 4 sqlite 数据库简单封装,主要处理数据库版本升级问题 5 微信.微博 API 简单封装 6 代码混淆 ...... github: https://github.com/lesliebeijing/MyAndroidFramework.git

网易新闻iOS版使用的开源组件

网易新闻iOS版在开发过程中曾经使用过的第三方开源类库.组件 1.AFNetworkingAFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功能强大, 现在许多人都用它取代 ASIHTTPRequest 2.Apple Reachability网络监测,可以参考下这篇文章iOS网络监测如何区分2.3.4G? 3.DOUAudioStreamer豆瓣的开源软件,DOUAudioStreamer 是 i

网易新闻iOS版开发使用的第三方框架和组件列表

网易新闻iOS版在开发过程中曾经使用过的第三方开源类库.组件 1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功能强大, 现在许多人都用它取代 ASIHTTPRequest 2.Apple Reachability 网络监测,可以参考下这篇文章iOS网络监测如何区分2.3.4G? 3.DOUAudioStreamer 豆瓣的开源软件,DOUAudioStreamer

新版网易新闻客户端应用iOS源码

这是一个不错的iOS项目源码. 源码下载: http://code.662p.com/view/11510.html 演示图:   1.这次更新的亮点是添加了天气效果以后也可以用网易新闻看天气预报了,各种轻微的动画效果也没有放过. 2.新版的网易新闻,整改了首页UI,在底部加上了tabbar,因此多了很多页面这里也都编了,但是无法交互.毕竟东西太多了,我觉得能点击看到效果就算不能进一步深入,就一个壳子也比全空没有强是吧.. 3.主页-主页的下方加了tabbar,nav的两个按钮做了改变 4.详情