美文网首页
网易栏目分类

网易栏目分类

作者: iOS猿_员 | 来源:发表于2019-06-18 14:20 被阅读0次

源代码

链接:https://pan.baidu.com/s/16Lyugu1mGoIK7s8skC-Yog
提取码:hyov

主要代码:

//
//  ViewController.m
//  网易栏目分类
//
//  Created by 许磊 on 2019/2/25.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "ViewController.h"
#import "ChangeColumnView.h"
#import "Constants.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    /**布局*/
    [self UIInit];

}

#pragma mark -------UIInit ---------
//界面布局
-(void)UIInit{

    //导航栏
    {
        //背景颜色
        self.navigationController.navigationBar.barTintColor = [UIColor redColor];

        //标题
        self.title = @"网易新闻";
        self.navigationController.navigationBar.titleTextAttributes = @{NSFontAttributeName:[UIFont fontWithName:@"Helvetica-Bold" size:17],NSForegroundColorAttributeName:[UIColor blackColor]};

        //左边的按钮
        UIImage *image = [[UIImage imageNamed:@"arrow_0"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
        UIBarButtonItem *listChangeButton = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStylePlain target:self action:@selector(listButtonDidClicked:)];
        listChangeButton.tintColor = [UIColor blackColor];
        self.navigationItem.leftBarButtonItem = listChangeButton;

        //右边的按钮
        UIBarButtonItem *columnChangeButton = [[UIBarButtonItem alloc] initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(editButtonDidClicked:)];
        columnChangeButton.tintColor = [UIColor blackColor];
        self.navigationItem.rightBarButtonItem = columnChangeButton;
    }

}

#pragma mark -------listButtonDidClicked: ---------
//列表平铺按钮被点击
-(void)listButtonDidClicked:(UIBarButtonItem *)sender{

    //Tag值判断按钮目前的状态 0-隐藏 1-显示
    if (sender.tag == 0) {

        //改变状态
        sender.tag = 1;
        //动画
        [UIView animateWithDuration:0.5 animations:^{
            sender.image = [UIImage imageNamed:@"arrow_1"];
        }];
        //显示
        [ChangeColumnView showColumnViewWithFrame:CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height-64)];

    } else{

        //改变状态
        sender.tag = 0;
        //动画
        [UIView animateWithDuration:0.5 animations:^{
            sender.image = [UIImage imageNamed:@"arrow_0"];
        }];
        //隐藏
        [ChangeColumnView hideColumnView];

    }

}

#pragma mark -------editButtonDidClicked: ---------
//编辑按钮被点击
-(void)editButtonDidClicked:(UIBarButtonItem *)sender{

    BOOL isEditing;

    //按钮文本改变
    if ([sender.title isEqualToString:@"编辑"]) {

        //编辑状态
        sender.title = @"完成";

        isEditing = YES;

    } else{

        //正常状态
        sender.title = @"编辑";

        isEditing = NO;

    }

    //发送消息
    [[NSNotificationCenter defaultCenter] postNotificationName:kEditStatusNotificationName object:@(isEditing)];

}

@end

//
//  Constants.h
//  网易分类
//
//  Created by 许磊 on 2019/2/25.
//  Copyright © 2019年 xulei. All rights reserved.
//

/**常量性东西 保持一致*/

#ifndef Constants_h
#define Constants_h

//消息的名称
#define kEditStatusNotificationName @"kEditStatusNotificationName"

//记录栏目的类型
typedef enum {
    kOperationTypeSelected,
    kOperationTypeMore
} kOperationType;

#endif /* Constants_h */

//
//  ChangeColumnView.h
//  网易分类
//
//  Created by 许磊 on 2019/2/24.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "CreatColumnItem.h"

@interface ChangeColumnView : UIView

/**提供一个类方法---显示视图*/
+(void)showColumnViewWithFrame:(CGRect)frame;

/**提供一个类方法---隐藏视图*/
+(void)hideColumnView;

/**按钮方法声明*/
-(void)itemDeleteButtonDidClicked:(UIButton *)sender;
-(void)itemButtonDidClicked:(CreatColumnItem *)sender;

@end

//
//  ChangeColumnView.m
//  网易分类
//
//  Created by 许磊 on 2019/2/24.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "ChangeColumnView.h"
#import "AppDelegate.h"
#import "OperationView.h"

//静态 单例模式
static ChangeColumnView *instance = nil;

@interface ChangeColumnView ()

/**管理已经显示的栏目的视图*/
@property (nonatomic,strong) OperationView *selectedOperationView;

/**管理没有显示的栏目的视图*/
@property (nonatomic,strong) OperationView *moreOperationView;

/**保存栏目数据*/
@property (nonatomic,strong) NSMutableArray *selectedArray;
@property (nonatomic,strong) NSMutableArray *moreArray;

@end

@implementation ChangeColumnView

//为了布局 重新initWithFrame
-(instancetype)initWithFrame:(CGRect)frame{

    self = [super initWithFrame:frame];

    if (self != nil) {

        self.backgroundColor = [UIColor colorWithRed:221/255.0 green:221/225.0 blue:221/255.0 alpha:1];

        //创建已经显示栏目视图
        self.selectedOperationView = [[OperationView alloc] initWithFrame: CGRectZero];
        _selectedOperationView.backgroundColor = [UIColor whiteColor];
        _selectedOperationView.type = kOperationTypeSelected;
        [self addSubview:_selectedOperationView];

        //创建还没有添加的栏目视图
        self.moreOperationView = [[OperationView alloc] initWithFrame:CGRectZero];
        _moreOperationView.backgroundColor = [UIColor whiteColor];
        _moreOperationView.type = kOperationTypeMore;
        [self addSubview:_moreOperationView];

        //加载数据
        [self loadData];

    }

    return self;

}

#pragma mark -------loadData ---------
//加载数据
-(void)loadData{

    //初始化数组
    self.selectedArray = [NSMutableArray arrayWithArray:@[@"体育", @"房产", @"NBA", @"娱乐", @"科技", @"游戏", @"军事", @"直播", @"音乐"]];
    self.moreArray = [NSMutableArray arrayWithArray:@[@"历史", @"影视", @"时尚", @"财经", @"数码", @"汽车"]];

    //传递数据
    self.selectedOperationView.itemNameArray = _selectedArray;
    self.moreOperationView.itemNameArray = _moreArray;

    //对子视图进行布局
    [self layoutIfNeeded];

}

#pragma mark -------layoutSubviews ---------
//布局子视图
//根据数据对子视图重新布局 frame
-(void)layoutSubviews{

    //计算选择的栏目视图的frame -> height
    NSInteger row1 = (_selectedArray.count-1)/4+1;
    self.selectedOperationView.frame = CGRectMake(0, 30, self.frame.size.width, row1*50+10);

    //计算没有选择的栏目视图的frame -> height
    NSInteger row2 = (_moreArray.count-1)/4+1;
    self.moreOperationView.frame = CGRectMake(0, _selectedOperationView.frame.origin.y+_selectedOperationView.frame.size.height+30, self.frame.size.width, row2*50);

}

#pragma mark -------showColumnView ---------
//显示视图
+(void)showColumnViewWithFrame:(CGRect)frame{

    //创建这个对象
    instance = [[ChangeColumnView alloc] initWithFrame:frame];
    instance.frame = CGRectMake(0, frame.origin.y, frame.size.width, 1);

    //类方法不能访问其实例对象的属性

    //1.找到应用程序的代理
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

    //2.得到window对应的视图控制器的view
    [appDelegate.window.rootViewController.view addSubview:instance];

    //动画方式 往下平铺 
    [UIView animateWithDuration:0.6 animations:^{
        instance.frame = frame;
    }];

}

#pragma mark -------hideColumnView ---------
//隐藏视图
+(void)hideColumnView{

    //动画方式 往上平铺
    [UIView animateWithDuration:0.6 animations:^{
        instance.frame = CGRectMake(0, instance.frame.origin.y, instance.frame.size.width, 1);
    }completion:^(BOOL finished){
        [instance removeFromSuperview];
    }];

}

#pragma mark -------itemDeleteButtonDidClicked: ---------
//item上删除按钮的事件
-(void)itemDeleteButtonDidClicked:(UIButton *)sender{

    NSLog(@"删除按钮");

    //需要删除栏目

    CreatColumnItem *columnButton = (CreatColumnItem *)sender.superview;

    //1.获取点击的item在数组里面的索引值
    NSInteger index = [self.selectedArray indexOfObject:columnButton.titleLabel.text];

    //2.删除selected里面的index对象
    [self.selectedArray removeObjectAtIndex:index];

    //3.在more  里面添加这个对象
    [self.moreArray addObject:columnButton .titleLabel.text];

    //4.将这个item移动到上方
    //传递数据
    self.selectedOperationView.itemNameArray = _selectedArray;
    self.moreOperationView.itemNameArray = _moreArray;

    [self setNeedsLayout];
    [self layoutIfNeeded];

}

#pragma mark -------itemButtonDidClicked: ---------
//item按钮被点击
-(void)itemButtonDidClicked:(CreatColumnItem *)sender{

    NSLog(@"按钮本身");

    if (sender.type == kOperationTypeMore) {

        //需要添加栏目

        //1.获取点击的item在数组里面的索引值
        NSInteger index = [self.moreArray indexOfObject:sender.titleLabel.text];

        //2.删除more里面的index对象
        [self.moreArray removeObjectAtIndex:index];

        //3.在selected里面添加这个对象
        [self.selectedArray addObject:sender.titleLabel.text];

        //4.将这个item移动到上方
        //传递数据
        self.selectedOperationView.itemNameArray = _selectedArray;
        self.moreOperationView.itemNameArray = _moreArray;

        [self setNeedsLayout];
        [self layoutIfNeeded];
    }
}

@end

//
//  ChangeColumnView.m
//  网易分类
//
//  Created by 许磊 on 2019/2/24.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "ChangeColumnView.h"
#import "AppDelegate.h"
#import "OperationView.h"

//静态 单例模式
static ChangeColumnView *instance = nil;

@interface ChangeColumnView ()

/**管理已经显示的栏目的视图*/
@property (nonatomic,strong) OperationView *selectedOperationView;

/**管理没有显示的栏目的视图*/
@property (nonatomic,strong) OperationView *moreOperationView;

/**保存栏目数据*/
@property (nonatomic,strong) NSMutableArray *selectedArray;
@property (nonatomic,strong) NSMutableArray *moreArray;

@end

@implementation ChangeColumnView

//为了布局 重新initWithFrame
-(instancetype)initWithFrame:(CGRect)frame{

    self = [super initWithFrame:frame];

    if (self != nil) {

        self.backgroundColor = [UIColor colorWithRed:221/255.0 green:221/225.0 blue:221/255.0 alpha:1];

        //创建已经显示栏目视图
        self.selectedOperationView = [[OperationView alloc] initWithFrame: CGRectZero];
        _selectedOperationView.backgroundColor = [UIColor whiteColor];
        _selectedOperationView.type = kOperationTypeSelected;
        [self addSubview:_selectedOperationView];

        //创建还没有添加的栏目视图
        self.moreOperationView = [[OperationView alloc] initWithFrame:CGRectZero];
        _moreOperationView.backgroundColor = [UIColor whiteColor];
        _moreOperationView.type = kOperationTypeMore;
        [self addSubview:_moreOperationView];

        //加载数据
        [self loadData];

    }

    return self;

}

#pragma mark -------loadData ---------
//加载数据
-(void)loadData{

    //初始化数组
    self.selectedArray = [NSMutableArray arrayWithArray:@[@"体育", @"房产", @"NBA", @"娱乐", @"科技", @"游戏", @"军事", @"直播", @"音乐"]];
    self.moreArray = [NSMutableArray arrayWithArray:@[@"历史", @"影视", @"时尚", @"财经", @"数码", @"汽车"]];

    //传递数据
    self.selectedOperationView.itemNameArray = _selectedArray;
    self.moreOperationView.itemNameArray = _moreArray;

    //对子视图进行布局
    [self layoutIfNeeded];

}

#pragma mark -------layoutSubviews ---------
//布局子视图
//根据数据对子视图重新布局 frame
-(void)layoutSubviews{

    //计算选择的栏目视图的frame -> height
    NSInteger row1 = (_selectedArray.count-1)/4+1;
    self.selectedOperationView.frame = CGRectMake(0, 30, self.frame.size.width, row1*50+10);

    //计算没有选择的栏目视图的frame -> height
    NSInteger row2 = (_moreArray.count-1)/4+1;
    self.moreOperationView.frame = CGRectMake(0, _selectedOperationView.frame.origin.y+_selectedOperationView.frame.size.height+30, self.frame.size.width, row2*50);

}

#pragma mark -------showColumnView ---------
//显示视图
+(void)showColumnViewWithFrame:(CGRect)frame{

    //创建这个对象
    instance = [[ChangeColumnView alloc] initWithFrame:frame];
    instance.frame = CGRectMake(0, frame.origin.y, frame.size.width, 1);

    //类方法不能访问其实例对象的属性

    //1.找到应用程序的代理
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

    //2.得到window对应的视图控制器的view
    [appDelegate.window.rootViewController.view addSubview:instance];

    //动画方式 往下平铺 
    [UIView animateWithDuration:0.6 animations:^{
        instance.frame = frame;
    }];

}

#pragma mark -------hideColumnView ---------
//隐藏视图
+(void)hideColumnView{

    //动画方式 往上平铺
    [UIView animateWithDuration:0.6 animations:^{
        instance.frame = CGRectMake(0, instance.frame.origin.y, instance.frame.size.width, 1);
    }completion:^(BOOL finished){
        [instance removeFromSuperview];
    }];

}

#pragma mark -------itemDeleteButtonDidClicked: ---------
//item上删除按钮的事件
-(void)itemDeleteButtonDidClicked:(UIButton *)sender{

    NSLog(@"删除按钮");

    //需要删除栏目

    CreatColumnItem *columnButton = (CreatColumnItem *)sender.superview;

    //1.获取点击的item在数组里面的索引值
    NSInteger index = [self.selectedArray indexOfObject:columnButton.titleLabel.text];

    //2.删除selected里面的index对象
    [self.selectedArray removeObjectAtIndex:index];

    //3.在more  里面添加这个对象
    [self.moreArray addObject:columnButton .titleLabel.text];

    //4.将这个item移动到上方
    //传递数据
    self.selectedOperationView.itemNameArray = _selectedArray;
    self.moreOperationView.itemNameArray = _moreArray;

    [self setNeedsLayout];
    [self layoutIfNeeded];

}

#pragma mark -------itemButtonDidClicked: ---------
//item按钮被点击
-(void)itemButtonDidClicked:(CreatColumnItem *)sender{

    NSLog(@"按钮本身");

    if (sender.type == kOperationTypeMore) {

        //需要添加栏目

        //1.获取点击的item在数组里面的索引值
        NSInteger index = [self.moreArray indexOfObject:sender.titleLabel.text];

        //2.删除more里面的index对象
        [self.moreArray removeObjectAtIndex:index];

        //3.在selected里面添加这个对象
        [self.selectedArray addObject:sender.titleLabel.text];

        //4.将这个item移动到上方
        //传递数据
        self.selectedOperationView.itemNameArray = _selectedArray;
        self.moreOperationView.itemNameArray = _moreArray;

        [self setNeedsLayout];
        [self layoutIfNeeded];
    }
}

@end

//
//  OperationView.m
//  网易分类
//
//  Created by 许磊 on 2019/2/25.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "OperationView.h"
#import "CreatColumnItem.h"
#import "Constants.h"

#define kPadding ((self.frame.size.width-20-70*4)/3)

@interface OperationView ()

/**存储创建的栏目视图*/
@property (nonatomic,strong) NSMutableArray *itemViewsArray;

/**记录编辑的状态*/
@property (nonatomic,assign) BOOL isEditing;

@end

@implementation OperationView

-(instancetype)initWithFrame:(CGRect)frame{

    self = [super initWithFrame:frame];

    if (self != nil) {

        //监听状态变化的消息
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusChanged:) name:kEditStatusNotificationName object:nil];

    }

    return self;
}

#pragma mark -------statusChanged: ---------
//状态切换的消息事件
-(void)statusChanged:(NSNotification *)notifi{
    NSLog(@"%@",notifi);

    //解析消息的内容
    self.isEditing = [notifi.object boolValue];

}

//重写set方法
-(void)setItemNameArray:(NSMutableArray *)itemNameArray{

    _itemNameArray = itemNameArray;

    //全部去除
    for (CreatColumnItem *item in self.subviews) {
        [item removeFromSuperview];
    }

    //初始化数组
    self.itemViewsArray = [NSMutableArray array];

    for (NSString *itemName in _itemNameArray) {

        //创建所有的栏目视图
        CreatColumnItem *item = [[CreatColumnItem alloc] initWithFrame:CGRectZero];
        item.itemName = itemName;
        item.type = self.type;
        item.isEditing = _isEditing;
        [self addSubview:item];

        //添加到数组中
        [self.itemViewsArray addObject:item];

    }

    //布局子视图
    [self layoutIfNeeded];

}

#pragma mark -------layoutSubviews ---------
-(void)layoutSubviews{

    for (int i = 0; i < _itemViewsArray.count; i++) {

        //创建栏目 第几行 第几列
        NSInteger row = i/4;
        NSUInteger colum = i%4;

        //取出对象
        CreatColumnItem *item = [_itemViewsArray objectAtIndex:i];

        //更改frame
        item.frame = CGRectMake(10+(70+kPadding)*colum, 10+(30+20)*row, 70, 30);

    }
}

@end

//
//  CreatColumnItem.h
//  网易分类
//
//  Created by 许磊 on 2019/2/25.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "Constants.h"

@interface CreatColumnItem : UIButton

/**接受数据-外部传来的栏目名称*/
@property (nonatomic,strong) NSString *itemName;

/**记录当前编辑的状态*/
@property (nonatomic,assign) BOOL isEditing;

/**记录这个栏目按钮在哪个栏目里面*/
@property (nonatomic,assign) kOperationType type;

@end

 //
//  CreatColumnItem.m
//  网易分类
//
//  Created by 许磊 on 2019/2/25.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "CreatColumnItem.h"
#import "ChangeColumnView.h"

@interface CreatColumnItem ()

/**删除按钮*/
@property (nonatomic,strong) UIButton *deleteBtn;

@end

@implementation CreatColumnItem

-(instancetype)initWithFrame:(CGRect)frame{

    self = [super initWithFrame:frame];

    if (self != nil) {

        //设置背景图片
        [self setBackgroundImage:[UIImage imageNamed:@"ring"] forState:UIControlStateNormal];

        //字体颜色
        [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

        //添加删除按钮
        self.deleteBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        _deleteBtn.frame = CGRectMake(-3, -2, 15, 15);
        [_deleteBtn setImage:[UIImage imageNamed:@"delete"] forState:UIControlStateNormal];
        _deleteBtn.hidden = YES;
        [_deleteBtn addTarget:self.superview.superview action:@selector(itemDeleteButtonDidClicked:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:_deleteBtn];

        //给背景按钮添加消息
        [self addTarget:self.superview.superview action:@selector(itemButtonDidClicked:) forControlEvents:UIControlEventTouchUpInside];

        //监听状态改变的消息
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusChanged:) name:kEditStatusNotificationName object:nil];

    }
    return self;
}

#pragma mark -------statusChanged: ---------
//状态切换的消息事件
-(void)statusChanged:(NSNotification *)notifi{
    NSLog(@"%@",notifi);

    //解析消息的内容
    self.isEditing = [notifi.object boolValue];

}

-(void)setItemName:(NSString *)itemName{

    _itemName = itemName;

    //设置文本
    [self setTitle:_itemName forState:UIControlStateNormal];
}

-(void)setIsEditing:(BOOL)isEditing{
    _isEditing = isEditing;

    if (self.type == kOperationTypeSelected) {

        //显现
        _deleteBtn.hidden = !_isEditing;
    }
}

@end

运行结果

运行结果

附一:开发流程

示意图
  • 1.创建一个按钮用来显示或者隐藏栏目,并添加事件(通过Tag值来区分状态 0隐藏 1显示)
  • 2.实现和隐藏栏目视图
    a.创建继承于UIView的ColumnView用于管理栏目
    b.提供show和hide方法用于快速便捷的显示和隐藏这个栏目视图(show需要找到当前程序的唯一代理AppDelegate找到里面的rootViewController.view作为栏目视图的父视图)
    c.添加和显示隐藏的动画(更改视图的高度达到上拉下铺的效果)
  • 3.创建OperationView用于管理每一个栏目按钮
    a.已经选择和没有选择的栏目视图
    b.加载数据
    c.实现layoutSubViews,对当前的子视图进行重新布局

(
自动调用:父视图的frame改变了,其layoutSubviews会被自动调用
将试图A添加到某个视图B上 这个A视图的layoutSubviews会被自动调用
手动调用:setNeedsDisplay layoutIfNeeded

补充一:系统自动调用layoutSubviews方法
1.初始化不会触发layoutSubviews,但是如果设置了不为CGRectZero的frame的时候就会触发。
2.addSubview会触发layoutSubviews
3.设置view的frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
4.滚动一个UIScrollView会触发layoutSubviews
5.旋转Screen会触发父UIView上的layoutSubviews事件  
6.改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件

补充二:手动刷新子对象布局
1.-layoutSubviews方法:这个方法,默认没有做任何事情,需要子类进行重写
2.-setNeedsLayout方法: 标记为需要重新布局,不立即刷新(下一次cycle立即刷新),但layoutSubviews一定会被调用,异步调用layoutIfNeeded立即刷新布局
3.-layoutIfNeeded方法:如果有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews
4.如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],实现布局
5.在视图第一次显示之前,标记总是“需要刷新”的,可以直接调用[view layoutIfNeeded]
)

  • 4.创建ColumnItem继承于UIButton

  • 5.相关说明:

a.利用type区分上下两个不同的OperationView

示意图1

b.利用block或者delegate一级一级传递数据

示意图2

c.利用消息中心传递数据

d.我们采用的是事件加到self.superview.superview身上,而不是按钮本身self

附二:单例方法

  • 目的是为了 确保整个程序中操作的都是这个对象。一般用于类方法,类方法调用简单。
  • 大家共享的,能够一直存在的,使用static静态的关键字
static ChangeColumnView *instance = nil;

-(instancetype)initWithFrame:(CGRect)frame{

    self = [super initWithFrame:frame];

    if (self != nil) {   

    }

    return self;
}

收录原文地址


推荐文集

* BAT—最新iOS面试题总结

相关文章

网友评论

      本文标题:网易栏目分类

      本文链接:https://www.haomeiwen.com/subject/qqlfqctx.html