09-百思不得姐(第九天)

今天需要做的界面如下(发段子界面):

1、初始化导航栏

  • 点击发段子按钮后push到DSPostWordViewController
- (void)buttonClick:(UIButton *)button
{
    [self cancelWithCompletionBlock:^{
        if (button.tag == 2) { // 段子

            DSPostWordViewController *postVc = [[DSPostWordViewController alloc] init];
            DSNavigationController *nav = [[DSNavigationController alloc] initWithRootViewController:postVc];
            UIViewController *rootVc = [UIApplication sharedApplication].keyWindow.rootViewController;
            [rootVc presentViewController:nav animated:YES completion:nil];
        }
    }];
}

首先把DSPostWordViewController包装成导航控制器,接着找出rootViewController,通过modal的方法弹出(这里不可以用self,因为self在点击button后就dismiss了)

  • 初始化导航栏内容
/**
 *  初始化导航栏
 */
- (void)setupNav
{
    self.title = @"发表文字";
    self.view.backgroundColor = DSThemeColor;

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:(UIBarButtonItemStyleDone) target:self action:@selector(cancleItemClick)];

    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"发表" style:(UIBarButtonItemStyleDone) target:self action:@selector(postItemClick)];

    self.navigationItem.rightBarButtonItem.enabled = NO;

    // 强制刷新
    [self.navigationController.navigationBar layoutIfNeeded];
}
UIBarButtonItem *barButtonItem = [UIBarButtonItem appearance];
    // normal状态下的item属性
    NSMutableDictionary *normalAttris = [NSMutableDictionary dictionary];
    normalAttris[NSForegroundColorAttributeName] = [UIColor blackColor];
    [barButtonItem setTitleTextAttributes:normalAttris forState:(UIControlStateNormal)];

    // disable状态下的item属性
    NSMutableDictionary *disableAttris = [NSMutableDictionary dictionary];
    disableAttris[NSForegroundColorAttributeName] = [UIColor lightGrayColor];
    [barButtonItem setTitleTextAttributes:disableAttris forState:(UIControlStateDisabled)];

一些通用性的设置可以放在自定义导航栏的initialize方法中只设置一次

由于enabled的设置要等显示完毕才会有这个效果,所以可以我们会想到把这句代码放到viewDidAppear方法中去,但是这样又会导致我们先看到黑色,然后看到看到灰色。所以最好的办法就是强制刷新(layoutIfNeeded

2、实现带占位文字的textView

想实现带占位文字的textView,可以用两种常规的方法,但前提都是自定义textView。

  • 第一种是将占位文字给画出来

    通过重写drawRect方法,将占位文字给画出来,但是这个方法有个缺点(当我们想要让textView可以滚动时,占位文字并不会和textView一起滚动),所以就衍生了下面一个做法!

  • 第二种在textView中添加一个label(这次使用的也是这种方法)

    1> 首先在initWithFrame方法中进行一些初始化设置,并且监听文字的改变来判断要不要显示占位文字。

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {

        // 垂直方向上永远有滚动效果
        self.alwaysBounceVertical = YES;

        // 默认字体颜色
        self.placeholderColor = [UIColor lightGrayColor];

        // 设置字体
        self.font = [UIFont systemFontOfSize:15];

        // 文字改变通知
        [DSNotificationCenter addObserver:self selector:@selector(textDidChange) name:UITextViewTextDidChangeNotification object:nil];
    }

    return self;
}
/**
 *  文本改变监听
 */
- (void)textDidChange
{
    self.placeholderLabel.hidden = self.hasText;
}

2> 在layoutSubView方法中更新label的尺寸

/**
 *  文本改变监听
 */
- (void)textDidChange
{
    self.placeholderLabel.hidden = self.hasText;
}

3> 在外界改变占位文字,占位文字颜色,字体这些属性时,label的尺寸就会发生改变,所以可以在赋值完文字后,调用layoutSubView方法及时更新尺寸

- (void)setPlaceholder:(NSString *)placeholder
{
    _placeholder = [placeholder copy];

    self.placeholderLabel.text = placeholder;

    [self setNeedsLayout];
}

- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
    _placeholderColor = placeholderColor;

    self.placeholderLabel.textColor = placeholderColor;

    [self setNeedsLayout];
}

- (void)setFont:(UIFont *)font
{
    [super setFont:font];

    self.placeholderLabel.font = font;

    [self setNeedsLayout];
}

4> 在外界改变text或attributedText时需要监听占位文字的显示或隐藏

- (void)setText:(NSString *)text
{
    [super setText:text];

    [self textDidChange];
}

- (void)setAttributedText:(NSAttributedString *)attributedText
{
    [super setAttributedText:attributedText];

    [self textDidChange];
}

5> 传递两个公开属性给外界(占位文字、占位文字颜色)

@property (nonatomic, strong) UIColor *placeholderColor;

@property (nonatomic, copy) NSString *placeholder;

3、添加底部的工具条

1> 添加+号按钮

/**
 *  创建+号按钮
 */
- (void)awakeFromNib
{
    UIButton *addButton = [[UIButton alloc] init];
    [addButton addTarget:self action:@selector(addButtonClick) forControlEvents:(UIControlEventTouchUpInside)];
    [addButton setImage:[UIImage imageNamed:@"tag_add_icon"] forState:(UIControlStateNormal)];
    addButton.size = addButton.currentImage.size;
//    addButton.size = [addButton imageForState:(UIControlStateNormal)].size;
//    addButton.size = [UIImage imageNamed:@""].size;
    [self.topView addSubview:addButton];
    self.addButton = addButton;
}

2> 监听按钮点击(跳转到DSAddTagViewController)

/**
 *  监听addButton点击
 */
- (void)addButtonClick
{
    DSAddTagViewController *addTagVc = [[DSAddTagViewController alloc] init];

    UINavigationController *nav =  (UINavigationController *)[UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController;

    [nav pushViewController:addTagVc animated:YES];
}

跳转至添加标签按钮界面。。。。。。

该界面的实现思路:

  • 首先添加一个整体的View
  • 添加一个textField
  • 输入文字时,显示底部的添加按钮
  • 点击添加按钮后,显示一个标签按钮到textField的前面

4、初始化导航栏和整体View

/**
 *  初始化导航栏
 */
- (void)setupNav
{
    self.view.backgroundColor = [UIColor whiteColor];
    self.title = @"添加标签";
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:(UIBarButtonItemStyleDone) target:self action:@selector(done)];
}
/**
 *  初始化整体内容
 */
- (void)setupContentView
{
    UIView *contentView = [[UIView alloc] init];
    contentView.x = DSTagButtonMargin;
    contentView.size = CGSizeMake(DSScreenW - contentView.x * 2, DSScreenH);
    contentView.y = 64 + DSTagButtonMargin;
    [self.view addSubview:contentView];
    self.contentView = contentView;
}

5、添加textField

/**
 *  初始化textField
 */
- (void)setupTextFiled
{
    __weak typeof(self) weakSelf = self;
    DSTagTextField *textField = [[DSTagTextField alloc] init];
    textField.deleteBlock = ^{
        if (weakSelf.textField.hasText) return ;
        [weakSelf tagButtonClick:[weakSelf.tagButtons lastObject]];
    };
    textField.delegate = self;
    [textField becomeFirstResponder];
    [textField addTarget:self action:@selector(textDidChange) forControlEvents:(UIControlEventEditingChanged)];
    textField.width = self.contentView.width;
    textField.height = 25;
    textField.placeholder = @"多个标签使用逗号或换行分隔";
    [self.contentView addSubview:textField];
    self.textField = textField;
}

我们需要监听textField内部文字的改变,来判断如何显示底部添加按钮的文字显示(这里不可以用代理,因为代理不能判断点击键盘顶部的文字,这时我们发现textField的继承自UIControl,所以可以添加监听事件)

6 、监听textField内部文字的改变

/**
 *  监听textField文字改变
 */
- (void)textDidChange
{
    [self updateTextFieldFrame];

    if ([self.textField hasText]) { // 有文字
        self.addButton.hidden = NO;
        self.addButton.y = CGRectGetMaxY(self.textField.frame) + DSTagButtonMargin;
        [self.addButton setTitle:[NSString stringWithFormat:@"添加标签: %@", self.textField.text] forState:(UIControlStateNormal)];

        // 获得最后一个字符
        NSString *text = self.textField.text;
        NSUInteger length = text.length;
        NSString *lastText = [self.textField.text substringFromIndex:length - 1];
        if ([lastText isEqualToString:@","] || [lastText isEqualToString:@","]) {
            // 去除逗号
            self.textField.text = [text substringToIndex:length - 1];
            // 添加标签按钮
            [self addButtonClick];
        }else {

        }

    }else { // 没有文字
        self.addButton.hidden = YES;
    }
}

首先得创建“添加按钮”(用懒加载)

- (UIButton *)addButton
{
    if (_addButton== nil) {
        UIButton *addButton = [[UIButton alloc] init];
        [addButton addTarget:self action:@selector(addButtonClick) forControlEvents:(UIControlEventTouchUpInside)];
        addButton.width = self.contentView.width;
        addButton.height = 35;
        addButton.backgroundColor = DSTagBg;
        // 设置内容水平向左对齐
        addButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        addButton.titleLabel.font = DSTagFont;
        // 左右间距
        addButton.contentEdgeInsets = UIEdgeInsetsMake(0, DSTagButtonMargin, 0, DSTagButtonMargin);
        [self.contentView addSubview:addButton];
        self.addButton = addButton;
    }
    return _addButton;
}

我们要根据有没有文字来设置添加按钮的显示和隐藏。

7 、监听“添加按钮”的点击

/**
 *  监听添加按钮的点击
 */
- (void)addButtonClick
{
    if (self.tagButtons.count == 5) { // 最多显示五个标签按钮
        [SVProgressHUD showErrorWithStatus:@"最多显示5个标签"];
        return ;
    }

    // 添加 标签按钮
    DSTagButton *tagButton = [[DSTagButton alloc] init];
    [tagButton addTarget:self action:@selector(tagButtonClick:) forControlEvents:(UIControlEventTouchUpInside)];
    [tagButton setTitle:[NSString stringWithFormat:@"%@", self.textField.text] forState:(UIControlStateNormal)];
    [self.contentView addSubview:tagButton];
    [self.tagButtons addObject:tagButton];

    self.addButton.hidden = YES;
    self.textField.text = nil;

    // 更新标签按钮和textField的位置
    [self updateTagButtonsFrame];
    [self updateTextFieldFrame];
}
/**
 *  更新标签按钮的位置
 */
- (void)updateTagButtonsFrame
{
    for (int i = 0; i < self.tagButtons.count; i++) {
        UIButton *tagButton = self.tagButtons[i];

        if (i == 0) { // 第一个位置标签按钮

            tagButton.x = 0;
            tagButton.y = 0;

        }else { // 其他位置的标签按钮

            // 找出前一个标签按钮
            UIButton *lastTagButton = self.tagButtons[i - 1];

            // 左边按钮所占宽度
            CGFloat leftWidth = CGRectGetMaxX(lastTagButton.frame);

            // 右边剩余宽度
            CGFloat rightWidth = self.contentView.width - leftWidth;

            if (rightWidth >= tagButton.width) { // 按钮显示在当前行

                tagButton.x = CGRectGetMaxX(lastTagButton.frame) + DSTagButtonMargin;
                tagButton.y = lastTagButton.y;

            }else { // 按钮显示在下一行

                tagButton.x = 0;
                tagButton.y = CGRectGetMaxY(lastTagButton.frame) + DSTagButtonMargin;

            }
        }
    }
}

/**
 *  更新textField的位置
 */
- (void)updateTextFieldFrame
{
    UIButton *lastTagButton = [self.tagButtons lastObject];

    CGFloat leftWidth = CGRectGetMaxX(lastTagButton.frame) + DSTagButtonMargin;

    // 更新textField的frame
    if (self.contentView.width - leftWidth - DSTagButtonMargin >= [self textFieldTextWidth]) {

        self.textField.x = leftWidth;
        self.textField.y = lastTagButton.y;

    }else {

        self.textField.x = 0;
        self.textField.y = CGRectGetMaxY(lastTagButton.frame) + DSTagButtonMargin;

    }
}

一旦点击了“添加按钮”后,我们应该及时更新“标签按钮”和“textField”的 位置!

8、监听“return”和“,”点击(相当于点击了“添加按钮”)

return键可以给textField设置代理来监听!

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if (textField.hasText) {
        [self addButtonClick];
    }

    return YES;
}

关于点击“,”,则是在textField文字改变时,拿出最后一个文字来判断!(上述代码已有写)

9、监听键盘删除按钮的点击

这个就不可以用textField的代理来解决了!而是应该重写textField的UIKeyInput协议里的deleteBackward方法,在这里告诉监听删除,由于得调用控制器方法,所以可以用Block来完成!在控制器中的block中写上删除操作,然后回调到textField的deleteBackward方法中来监听删除按钮的点击!(删除操作初始化textField代码中)

- (void)deleteBackward
{
    !self.deleteBlock ? : self.deleteBlock();

    [super deleteBackward];
}

10、发布界面和添加标签按钮界面之间的数据传递

这个时候,在我们添加了标签按钮后,需要在发布界面的工具条中更新按钮!所以可以在点击了完成item后,利用Block将当前的标签按钮文字数组传递过去,然后在push添加标签按钮控制器时,调用该block,根据传递的标签文字来创建label!

/**
 *  右侧item点击
 */
- (void)done
{
    // 传递数据给上一个控制器
//    NSMutableArray *tags = [NSMutableArray array];
//    for (DSTagButton *tagButton in self.tagButtons) {
//        [tags addObject:tagButton.currentTitle];
//    }

    NSArray *tags = [self.tagButtons valueForKeyPath:@"currentTitle"];
    // 将tags传递给这个block
    !self.tagBlock ? : self.tagBlock(tags);

    [self.navigationController popViewControllerAnimated:YES];
}
/**
 *  创建标签label
 */
- (void)createTagLabels:(NSArray *)tags
{
    // 移除之前的标签(一定要先移除lable,然后清空数据)
    [self.tagLabels makeObjectsPerformSelector:@selector(removeFromSuperview)];
    [self.tagLabels removeAllObjects];

    // 1.创建标签label,并设置frame
    for (int i = 0; i < tags.count; i++) {
        UILabel *tagLabel = [[UILabel alloc] init];
        tagLabel.textAlignment = NSTextAlignmentCenter;
        tagLabel.text = tags[i];
        tagLabel.textColor = [UIColor whiteColor];
        tagLabel.backgroundColor = DSTagBg;
        [tagLabel sizeToFit];
        tagLabel.width += DSTagButtonMargin * 2;
        [self.topView addSubview:tagLabel];
        [self.tagLabels addObject:tagLabel];

        if (i == 0) { // 第一个位置标签label

            tagLabel.x = 0;
            tagLabel.y = 0;

        }else { // 其他位置的标签label

            // 找出最后一个标签label
            UILabel *lastTagLabel = self.tagLabels[i - 1];

            // 左边label所占宽度
            CGFloat leftWidth = CGRectGetMaxX(lastTagLabel.frame) + DSTagButtonMargin;

            // 右边剩余宽度
            CGFloat rightWidth = DSScreenW - 2 * DSTagButtonMargin - leftWidth;

            if (rightWidth >= tagLabel.width) { // label显示在当前行

                tagLabel.x = leftWidth;
                tagLabel.y = lastTagLabel.y;

            }else { // label显示在下一行

                tagLabel.x = 0;
                tagLabel.y = CGRectGetMaxY(lastTagLabel.frame) + DSTagButtonMargin;

            }
        }
    }

    // 2.更新+号按钮的frame
    UILabel *lastTagLabel = [self.tagLabels lastObject];

    // 标签lable所占的宽度
    CGFloat leftWidth = CGRectGetMaxX(lastTagLabel.frame) + DSTagButtonMargin;

    if (self.topView.width - leftWidth - DSTagButtonMargin >= self.addButton.width) { // +号按钮显示在当前行

        self.addButton.x = leftWidth;
        self.addButton.y = lastTagLabel.y;

    }else { // +号按钮显示在下一行

        self.addButton.x = 0;
        self.addButton.y = CGRectGetMaxY(lastTagLabel.frame) + DSTagButtonMargin;

    }
}

提示:这个调用block,根据标签文字创建label的代码已经在上面的+号按钮点击方法中了!

11、添加默认标签,自动算工具条高度

自动计算高度可以先算出+号按钮的最大y值,然后加上间距和工具条高度,就可以自动算出高度了!但是这个时候会有一个小问题,就是键盘在弹出后,工具条的y值就已经固定了,这个时候改变工具条的高度就会导致工具条往上移动,中间会空出一段距离!因此应该在算出工具条高度后,及时改变y值!

这一步写在- (void)createTagLabels:(NSArray *)tags方法中

// 3.更新高度
    CGFloat oldH = self.height;
    self.height = CGRectGetMaxY(self.addButton.frame) + 45;
    self.y -= self.height - oldH;
时间: 2024-08-04 07:14:42

09-百思不得姐(第九天)的相关文章

iOS开发——完整项目实战OC篇&amp;百思不得姐第九天

百思不得姐第九天 一:点语法 点语法的本质是生成发送消息或者生成setter方法 二:获取手机时间的年和对应时间年是否一样 比如下面常见时间处理 方法1:(需要分别比较年月日) 方法2:(好处就是可以同时随便比较不同年月日) 如果时同一天就需要处理不不同的值 或者 最后一个昨天: 最终日期处理 三:Cell循环利用中,不使用缓存池中获取的cell的内容, 判断对应的类型,根据类型显示或者隐藏 四:新方法 传入字体和规定的矩形框计算,文字的高度 使用如下: 五:禁止每次计算cell高度 1:字典-

2019虫师自动化 Python接口自动化虫师 robotframework虫师 虫师接口自动化源码下载

第一套:Python虫师自动化 [5.1G]┃ ┣━━Python接口测试 [2.7G]┃ ┃ ┣━━code [23.9K]┃ ┃ ┃ ┗━━myweb01.zip [23.9K]┃ ┃ ┣━━Python Web 接口开发与测试7_28.pdf [6.1M]┃ ┃ ┣━━02.(第二节)python_install.mp4 [82M]┃ ┃ ┣━━03.(第三节)python_calss_and_mudule.mp4 [126.9M]┃ ┃ ┣━━04.(第四节)python_excepti

便是徐荒所带的

自己没趣走开了便是赵青衫以及http://weibo.com/2015.09.16/p/1001603887253242939273http://weibo.com/2015.09.16/p/1001603887253247120848http://weibo.com/2015.09.16/p/1001603887253247133649http://weibo.com/2015.09.16/p/1001603887253247133651http://weibo.com/2015.09.16/

百度房间撒谎发喀什经济法老师

http://www.ebay.com/cln/non.shua/cars/167418482013/2015.02.09 http://www.ebay.com/cln/lehu497/cars/167065144019/2015.02.09 http://www.ebay.com/cln/gaza240/cars/167530469015/2015.02.09 http://www.ebay.com/cln/go_qi26/cars/167224324018/2015.02.09 http:

怪我北灵院不给

要不就算平局吧都是显得极为http://weibo.com/2015.09.16/p/1001603887639781581729http://weibo.com/2015.09.16/p/1001603887639785818588http://weibo.com/2015.09.16/p/1001603887639790012974http://weibo.com/2015.09.16/p/1001603887639794164941http://weibo.com/2015.09.16/p

一道人影漫步而

一道全身包裹在不少人心头一跳http://weibo.com/09.16/2015/p/1001603887643111873409http://weibo.com/09.16/2015/p/1001603887643116067799http://weibo.com/09.16/2015/p/1001603887643120285680http://weibo.com/09.16/2015/p/1001603887643128674390http://weibo.com/09.16/2015/

移动互联网广告 - 第九更 - 互联网广告精准定向技术 - 2016/12/09

[总结]互联网精准广告定向技术 [致敬原作者:NiuGuoZhu - http://www.iamniu.com/2012/03/10/geographical-orientation/] 截止今天,关于精准广告定向技术的介绍已经全部wanc.jieshaode写作初衷是总结自己的知识,将知识片段的.隐形的转化为可以向别人讲述.能够给人帮助的.在总结的过程中自己也提升了很多,同时希望这些内容能够切实的给刚进入这个行业的同学以帮助.为了查看方便,特把内容进行汇总. 基础知识: 1.Http Hea

第九周PSP&amp;进度条

PSP 一.表格: D日期     C类型 C内容 S开始时间 E结束时间 I时间间隔 T净时间(mins) 预计花费时间(mins) 11月11号 讨论 讨论beta发布 09:00 09:54 12 42 30   编码 编写代码修补漏洞 17:37 19:43 18 108 120 11月12号 调查 用户调查报告调查与分析 10:15 10:45 5 85 90 11月14号 站立会议 分配各个成员任务 13:00 13:30 0 30 30   编写 编写new NABCD  15:0

2045331 《Java程序设计》第09周学习总结

2045331 <Java程序设计>第09周学习总结 教材学习内容总结 第十六章 整合数据库 16.1.1JDBC简介 1.JDBC是用于执行SQL的解决方案,开发人员使用JDBC的标准接口,数据库厂商则对接口进行操作,开发人员无须接触底层数据库驱动程序的差异性. 2.厂商在操作JDBC驱动程序时,依方式可将驱动程序分为4种类型: ·Type 1:JDBC-ODBC Bridge Driver ·Type 2:Native API Driver ·Type 3:JDbc-Net Driver

JAVA年度安全 第九周 X-FRAME-OPTIONS

What is it and why should I care? X-Frame-Options(在草拟的标准中已经移除X-,只保留Frame-Options)是一个新技术用来指定网站页面是否允许嵌入IFrame页面.这样能够解决点击劫持(clickjacking)攻击. 此技术是基于每个页面的HTTP响应头特定参数实现的.支持(X-)Frame-Options头参数的浏览器根据标准会允许或禁用当前页面上的IFrame页面. What shouldI do about it? 此方法同样也是一