作者声明
因跟人能力问题,文中不免有错误之处,欢迎各位读者交流,批评,指正!
摘要
在上文的基础上,重构“qq表情排列”,主要的原则就是:将公共代码提取到一个方法中,供其它方法调用,不同的地方通过传递参数来实现。主要包括添加表情代码和排序代码。
实例
viewController h代码
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
- (IBAction)sortImages:(UISegmentedControl *)sender;
#pragma mark 待改进1:是否可以通过其它方法将其省略?
// 仅仅是为了在加号的监听事件调用的方法中得到segment的值。
@property (weak, nonatomic) IBOutlet UISegmentedControl *segment;
@end
viewController m代码
//
// ViewController.m
// qq表情排序(按老师的思路重写一遍)
//
// Created by dqw on 15/5/7.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import "ViewController.h"
#define KImageWH 50 // 每个图片的长宽
#define No 10 // 初始化图片的个数。
@interface ViewController ()
@end
@implementation ViewController
#pragma mark 1. 在view加载完毕后加载图片。
- (void)viewDidLoad {
[super viewDidLoad];
// 加载图片。
for (int i = 0; i < No; i++) {
[self addImageWithNo:i AtIndex:i + 1 isInitial:YES];
}
// 加载后按2列排序。
[self sortImagesWithCount:No InColumns:2];
}
#pragma mark 2. 定义加载单个图片方法
- (void)addImageWithNo:(int)imageNo AtIndex:(int)index isInitial:(BOOL)isInitial
{
NSString *newImageName = [NSString stringWithFormat:@"%d.png",imageNo];
UIImage *newImage = [UIImage imageNamed:newImageName];
// 定义父类指针。
UIView *newImageView;
#pragma mark 注意点1:最后一个是button类型。
// 创建最后一个加号(button类型)
if ((imageNo == (No -1)) && isInitial ) {
newImageView = [[UIButton alloc]init];
#pragma mark 重点1:多态。
// 多态,强制类型转换后才能调用子类方法。
UIButton *temp = (UIButton *)newImageView;
[temp setImage:newImage forState:UIControlStateNormal];
// 为按钮添加监听事件。
[temp addTarget:self action:@selector(addImage) forControlEvents:UIControlEventTouchUpInside];
}
// 创建非最后一个加号,或者随机图片。
else
{
newImageView = [[UIImageView alloc]init];
// 多态,强制类型转换后才能调用子类方法。
UIImageView *temp = (UIImageView *)newImageView;
temp.image = newImage;
}
#pragma mark 待改善1:是否可以简化合成
#pragma mark 疑问1:仔细研究这三种插入方法。
// 初始化和随机插入两种情况,该部分要考虑一下是否可以合成。
if (isInitial) {
[self.view insertSubview:newImageView atIndex:index];
}
else{
[self.view insertSubview:newImageView belowSubview:self.view.subviews[index]];
}
}
#pragma mark 3. 定义图片排序方法
- (void)sortImagesWithCount:(int)count InColumns:(int)column
{
#pragma mark 注意点2:动画的位置。
// 动画放在这里更合适,因为位置值的改变就这这里发生。
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
// 图片y方向的起始位置和间距。
CGFloat startY = 10;
CGFloat distanceY = 50;
CGFloat startX;
CGFloat x;
CGFloat y;
startX = (self.view.frame.size.width -column * KImageWH) / (column + 1);
// 多态,父类指针。
UIView *tempView;
for (int i = 0; i < count; i++) {
x = startX + (startX + KImageWH) * (i % column);
y = startY + (distanceY + KImageWH) * (i / column);
tempView = self.view.subviews[i + 1];
tempView.frame = CGRectMake(x, y, KImageWH, KImageWH);
}
[UIView commitAnimations];
}
#pragma mark 4. 监听segment的值。
- (IBAction)sortImages:(UISegmentedControl *)sender {
// [UIView beginAnimations:nil context:nil];
//
// [UIView setAnimationDuration:1.0];
int column = sender.selectedSegmentIndex + 2;
// 更新个数。
int count = self.view.subviews.count;
[self sortImagesWithCount:count -1 InColumns:column];
// [UIView commitAnimations];
}
#pragma mark 5. 定义添加随机图片的方法(供加号监听事件调用)
- (void)addImage
{
#pragma mark 待改善2:是否可以合成到添加图片方法中?
#pragma mark 疑问2:监听事件调用该方法时如果该方法有参数则如何传递参数?
int imageNo = arc4random() % 9;
int count = self.view.subviews.count;
// index参数和插入的方法对应。
[self addImageWithNo:imageNo AtIndex:count - 1 isInitial:NO];
int column = _segment.selectedSegmentIndex + 2;
// 注意此处的count,因为已经add过了,所以此处count不-1.
[self sortImagesWithCount:count InColumns:column];
}
@end
重点 难点 注意点
- 如KImageWH,宏定义的时候第一个字目写K,可以用后面的WH表示一个单词width,但是一般宏名是全大写,单词简化也是取单词前缀。
- 将表情的添加方法和表情的排序方法提取,体会这样的模块化思想,更加灵活。
- 多态:用同样的父类uiview指针指向子类uiimageview和uibutton,但是在调用子类方法时,要强制类型转换。
- 动画的位置,避免重复写,放在动画发生的代码块中。
- 实施的更新subviews的个数。
疑问
- 为一个控件添加监听事件时,所调用的方法如果有参数,则该参数如何传递进去??
- 三种插入方法的区别?
待完善内容
- .h文件待改进1:@property segment 是否可以省略?
- 单词的缩写规则。
- .m文件待改进1,2:代码进一步合并简化。
- 添加storyboard,还有以前的。
- 这一部分的视频和实例代码还没有看。