UI相关类继承关系

UIView 常见属性和方法

1. UIView属性

Controller的viewDidLoad方法:当所有控件加载完毕后调用,相当于Android中View的onFinishInflate方法;

UIView superview 获得自己的父控件对象;

NSArray subview 获得自己的子控件对象,用数组NSArray保存;

NSInteger tag 控件的ID标示,父控件可以通过tag来找到对应的子控件;

CGRect fram 控件所在矩形框的位置和尺寸(以父控件的左上角为坐标原点);

CGRect bounds 控件所在矩形框的位置和尺寸(以自己左上角为坐标原点,所以bounds的x\y永远为0);

CGPoint center 控件中点的位置(以父控件 的左上角为坐标原点);

CGAffineTransform transform 控件的形变属性(可以设置旋转角度、比例缩放、平移等属性);

UIColor backgroundColor 背景颜色

BOOL hidden 设置是否隐藏

CGFloat alpha 透明度(0~1)

CGFloat opaque 不透明度(0~1)

BOOL userInteractionEnabled 默认YES,是否可以和用户交互(相当于android enable)

UIViewContentMode contentMode 内容显示的模式(android:gravity =”center_vertical”)

另外UIView中有很多扩展协议,用来处理控件的属性

修改UIView的尺寸(宽高):frame、bounds

修改UIView的位置:frame(左上角的位置)、center(中点的位置)

2. UIView方法

addSubview 添加子控件,被添加到最上面(subviews中的最后面)

removeFromSuperview 将自己从父控件中移除

viewWithTag 父控件可以根据这个tag标示找到对应的子控件(遍历所有的子控件)findViewById

insertSubview:atIndext 添加子控件到指定的位置

beginAnimations: context: 执行动画

/…需要执行动画的代码…/

commitAnimations

利用代码块block执行动画

/*
 *duration 动画持续时间
 *animations 存放需要执行动画的代码
 *completion 存放动画执行完毕后需要执行的代码
 */
 + (void)animateWithDuration:(NSTimeInterval) duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion

3. UIControl

只要继承了UIControl就能简单处理一些事件(点击事件、值改变事件);

继承了UIControl的子类有:UIButton、UISlider、UISwitch、UIDatePicker等等;

当需要监听一个子控件的事件的时候,先要看它是否继承自UIControl,再看它内部是否有delegate属性(代理);

常用属性:

enable 是否处理事

contentVerticalAlignment 内容在垂直方向上的排布方式

contentHorizontalAlignment 内容在水平方向上的排布方式

常用方法

addTarget 添加事件监听器(参数:监听器对象、事件触发回调方法、事件类型)

removeTarget 删除事件监听器

allTargets 获取所有的监听器对象集合


常用控件

1. UIImageView 图片显示控件(android ImageView)

@property (weak, nonatomic) IBOutlet UIImageView *imageView;
self.imageView.image = [UIImage imageNamed:@“icon.png"];

设置图片展示模式(android ImageView 的scaleType属性):

2. UISlider可拖动的进度条 (android SeekBar

@property (weak, nonatomic) IBOutlet UISlider *slider;
//设置最大值
self.slider.maximumValue = self.imageDate.count;
//设置最小值
self.slider.minimumValue = 1;
//设置当前值
self.slider.value = 1;

3. UIButton按钮

常用属性

titleLable 获取内部的UILabel对象

imageView 获取内部的UIImageView对象

常见方法

setTitle:forState: 设置背部UILable显示的文本内容(不能写btn.titleLabel.text = @"123"

setTileColor:forState 设置内部UILabel文字颜色

setTileShaowColor:forState 设置内部UILabel文字的阴影颜色

setImage:forState 设置内部UIImageView的图片(不能写btn.iamgeView.image =[ UIImage imagedName:@"0.png"])

setTileShaowColor:forState 设置内部UILabel文字的阴影颜色

setBackgroundImage:forState 设置背景图片

下面方法可以获取不同状态下的一些属性值:

titleForState 获取某个状态下显示文字

titleColorForState 获取某个状态下文字颜色

titleShadowColorForState 获取某个状态下文字阴影颜色

imageForState 获取某个状态下图片

backgroundImageForState 获取某个状态下背景图片

下面两个方法需要交给子类重写(继承UIButton):

titleRectForContentRect 返回内部UILabel的frame(位置和尺寸)

imageRectForContentRect 返回内部UIImageView的frame(位置和尺寸)

示例代码

普通按钮custom

//创建按钮
UIButton*orangeBtn = [[UIButtonalloc]init];
orangeBtn.tag=kOrangeTag;
//设置按钮的frame(位置和尺寸)
orangeBtn.frame=CGRectMake(100,100,100,100);
//设置背景色
orangeBtn.backgroundColor= [UIColororangeColor];
//设置按钮文字
[orangeBtnsetTitle:@"普通"forState:UIControlStateNormal];
[orangeBtnsetTitle:@"按下"forState:UIControlStateHighlighted];
//设置按钮按下时文字颜色
[orangeBtnsetTitleColor:[UIColorredColor]forState:UIControlStateHighlighted];
UIButton*btn = [[UIButtonalloc]init];
//添加按钮的唯一标示
btn.tag = 1;
//根据图片名称去项文件系统中加载图片对象
UIImage*imageNormal = [UIImageimageNamed:@"sub_black_prev.png"]];
UIImage*imagePress = [UIImageimageNamed:@"sub_blue_prev.png"]];
//设置按钮背景图片
[btnsetBackgroundImage:imageNormalforState:UIControlStateNormal];
[btnsetBackgroundImage:imagePressforState:UIControlStateHighlighted];
//设置按钮的frame(位置和尺寸)//btn.frame = CGRectMake(point.x, point.y, imageNormal.size.width, imageNormal.size.height);
   /*
     struct CGRect {
     CGPoint origin;
     CGSize size;
     };
    */
btn.frame = (CGRect){point, imageNormal.size};
//绑定监听
[btn addTarget:self action:@selector(directionBtnClick:) forControlEvents:UIControlEventTouchUpInside];
//根据按钮的tag获取子控件
UIButton*orangeBtn = [self.viewviewWithTag:kOrangeTag];
CGPoint center = orangeBtn.center;
staticCGFloatDELETE =50;
center.y += DELETE;
//重新赋值按钮的中点
orangeBtn.center= center;

根据系统自带样式类型创建

//创建一个加号的按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
btn.center = CGPointMake(100, 100);

4. UILable 文本 (android TextView)

常用属性:

text 显示文本内容

textColor 文字颜色

font 字体

shadowColor 文字的阴影颜色

shadowOffset 阴影的偏差距离(width水平方向的偏差距离,整数右边;height垂直方向上的偏差距离,正数下边)

textAlignment 设置文字的排列方式(偏左、偏右、居中)

numberOfLines 允许文字最多几行(默认1,如果是0,自动换行)

5. UIText 文本输入框(android EditText)

6. UISwitch 开关

#pragma mark 开关值改变监听
-(IBAction)switchChanged:(UISwitch *)sender {
    NSLog(@"开关值%d", sender.isOn);
    self.view.backgroundColor = sender.isOn?[UIColor darkGrayColor]:[UIColor whiteColor];
}

7. UIDatePicker日期控件

-(void) viewDidLoad{
    [super viewDidLoad];

    UIDatePicker *picker = [[UIDatePicker alloc] init];
    //设置区域
    picker.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"];
    //设置模式(显示日期还是时间)
    picker.datePickerMode = UIDatePickerModeDate;

}
#pragma mark 拖动时间改变后监听
-(IBAction)dateChanged:(UIDatePicker *) dataPicker{
    //获取日期值
    NSDate * date = dataPicker.date;
    //格式化日期
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyy/MM/bb";

    self.label.text = [formatter stringFromDate:date];
}

8. UIPickerView 跟android Spinner相似

设置数据源和代理(监听)为控制器,控制器遵循数据源河代理的协议,重写协议的方法:

  • 简单使用
#pragma mark 控制器充当UIPickerView的数据源和代理,必须遵循两个协议
@interface ViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
@property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
@end

#import "ViewController.h"
@interface ViewController()
@property (nonatomic,strong) NSArray *oneCol;
@property (nonatomic,strong) NSArray *towCol;
@end

@implementation ViewController
-(void) viewDidLoad{
    self.oneCol = @[@"00", @"01", @"02", @"03"];
    self.towCol = @[@"000", @"001", @"002", @"003", @"004"];
}
#pragma mark - UIPickerView的数据源方法(返回第component列的行数)
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{

    return component == 0?self.oneCol.count:self.towCol.count;
}
#pragma mark - UIPickerView的数据源方法(返回列数)
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 2;
}
#pragma mark - UIPickerView的代理方法(返回第component列第row航显示的字符串数据-设置数据)
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    if(component==0){
        return self.oneCol[row];
    }else{
        return self.towCol[row];
    }
}
#pragma mark - UIPickerView的代理方法(选中了某一行调用)
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    if(component==0){
        NSString *leftRow = self.oneCol[row];
        //获取第二列当前停留的行数
        int towRow = [pickerView selectedRowInComponent:1];
        NSString *rightRow = self.towCol[towRow];
        NSLog(@"第%d列:%@-----第%d列:%@", component, leftRow, 1, rightRow);
    }else{
        NSString *rightRow = self.towCol[row];
        int oneRow = [pickerView selectedRowInComponent:0];
        NSString *leftRow = self.oneCol[oneRow];
        NSLog(@"第%d列:%@-----第%d列:%@", 0, leftRow, 1, rightRow);
    }
}
@end
  • 显示自定义条目
#pragma mark 修改每一行的高度
-(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
    return 70;
}
#pragma mark 返回地component列第row行需要显示的控件
-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
    UIView *rowView = [[UIView alloc] init];
    CGFloat rowViewH = 40;
    CGFloat rowViewW = 200;
    rowView.bounds = CGRectMake(0, 0, 200, rowViewH);

    //国家名称
    UILabel *nameLable = [[UILabel alloc] init];
    CGFloat nameW = 70;
    nameLable.frame = CGRectMake(0, 0, nameW, rowViewH);
    nameLable.textAlignment = NSTextAlignmentCenter;
    nameLable.text = @"asdfsd";
    [rowView addSubview:nameLable];
    //国旗
    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.frame = CGRectMake(nameW, 0, rowViewW-nameW, rowViewH);
    imageView.image = [UIImage imageNamed:@"zhongguo.jpg"];
    [rowView addSubview:imageView];

    return rowView;
}

9. UIScollView (android ScollView)

UIPageControl 请见:分页显示

当子控件内容太多或者子控件太大显示不全时,用UIScrollView实现滚动

  • 常用属性

    CGPoint contentOffset UIScrollView当前滚动到哪个位置了(相对于内容左上角的坐标)

    CGSize contentSize UIScrollView的滚动范围(内容的尺寸)

    UIEdgeInsets contentInset 这个属性可以在四周增加滚动范围



    BOOL bounces; 是否有弹簧效果

    BOOL scrollEnabled; 是否能滚动

    BOOL showsHorizontalScrollIndicator 是否显示水平方向的滚动条

    BOOL showsVerticalScrollIndicator 是否显示垂直方向的滚动条

    UIScrollViewIndicatorStyle indicatorStyle 设定滚动条的样式

    BOOL tracking 是否正在被拖拽

    BOOL dragging 当touch后还没有拖动的时候值是YES,否则是NO

    BOOL decelerating 是否正在减速

  • 使用示例:

UIImage *image = [UIImage imageNamed:@"1.png"];
//通过图片初始化UIImageview,这样ImageView的宽高就跟图片宽高一样了
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[self.scroll addSubview:imageView];
//self.scroll.frame.size  UIScrollView控件的大小(可视范围)
//设置内容的宽高(可滚动范围)
self.scroll.contentSize = image.size;
//为UIScrollView设置上下左右额外的可拖动范围(空隙)
self.scroll.contentInset = UIEdgeInsetsMake(10, 20, 30, 40);
self.scroll.backgroundColor = [UIColor lightGrayColor];
   //self.scroll.contentOffset.x += 10;//不能直接修改对象的结构体属性的成员
//修改UIScrollView当前拖动的位置(相对于内容左上角的坐标)
CGPoint offset = self.scroll.contentOffset;
//向左移动(查看右边的内容)
offset.x += 50;
//执行动画
[UIView animateWithDuration:0.3 animations:^{
    self.scroll.contentOffset = offset;
}];
  • 手势识别缩放
@property(nullable,nonatomic,weak) id<UIScrollViewDelegate>        delegate;
iOS中的UIScrollView已经封装了手势识别,不需要我们分析手指位置以及滑动方向,只需要设置上面的代理属性即可(代理可以理解为回调接口),这个代理需要遵守UIScrollViewDelegate协议;然后选择性的实现里面的回调方法。
而android中如果要实现此功能,需要我们分析多点触控以及手指位置和滑动方向来判断缩放还是放大。</br>

步骤:

①、设置UIScrollView的代理delegate为控制器,控制器遵守UIScrollViewDelegate协议

②、设置最大和最小缩放比例maximumZoomScaleminimumZoomScale

③、让代理对象实现方法,返回需要缩放的子控件

//设置最大缩放比例
self.scroll.maximumZoomScale = 2;
//设置最小缩放比例
self.scroll.minimumZoomScale = 0.5;
 #pragma mark -UIScrollView的代理方法:返回需要进行缩放的空间(必须是UIScrollVIew的子控件)
(nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
    return self.imageView;
}
  • 代理中其他方法:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;    // any offset changes offset属性变化时调用(在被拖动)
// 将要开始拖拽时调用
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
// 拖拽将要结束时调用
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0);
// 拖拽结束时调用
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;   // called on finger up as we are moving
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;      // ScrollView减速完毕后调用
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView; // called when setContentOffset/scrollRectVisible:animated: finishes. not called if not animating

- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;     // 返回需要进行缩放的子控件
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view NS_AVAILABLE_IOS(3_2); // 将要缩放之前调用
- (void)scrollViewDidZoom:(UIScrollView *)scrollView NS_AVAILABLE_IOS(3_2); // any zoom scale changes 缩放时调用
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale; // 缩放完毕后调用
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;   // return a yes if you want to scroll to the top. if not defined, assumes YES
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;      // called when scrolling animation finished. may be called immediately if already at top
  • 分页显示(android ViewPager)

#define kCount 5
@interface ViewController ()
@property (nonatomic, weak) UIPageControl *_pageControl;
@property (nonatomic, weak) UIScrollView *_scrollView;
@end

@implementation ViewController
- (void)viewDidLoad {
   [super viewDidLoad];
   for(int i = 0; i<self.view.subviews.count; i++){
        [self.view.subviews[i] removeFromSuperview];
    }
    //分页显示
    //1、添加UIScrollView
    UIScrollView *scrollView = [[UIScrollView alloc] init];

    //设置填充父窗体
    scrollView.frame = self.view.bounds;
    [self.view addSubview:scrollView];
    self._scrollView = scrollView;

    CGFloat scrollWdith = scrollView.frame.size.width;
    CGFloat scrollHight = scrollView.frame.size.height;

    // 2、添加所有的ImageView
    for(int i = 0;i<=kCount;i++){
        //加载图片
        NSString *imageName = [NSString stringWithFormat:@"pages.bundle/%d.jpg", i];
        UIImage *image = [UIImage imageNamed:imageName];
        UIImageView *imageView = [[UIImageView alloc] init];
        imageView.image = image;
        imageView.frame = CGRectMake((i-1)*scrollWdith, 0, scrollWdith, scrollHight);
        [scrollView addSubview:imageView];

    }

    //3、设置滚动范围
    scrollView.contentSize = CGSizeMake(kCount*scrollWdith, 0);
    //隐藏滚动条
    scrollView.showsHorizontalScrollIndicator = NO;
    //4、开启分页功能(按照ScrollView的宽度将内容分为若干页,正好ImageView的宽度相等,就实现了分页)
    scrollView.pagingEnabled = YES;

    //5、添加PageControl
    UIPageControl *pageControl = [[UIPageControl alloc] init];
    pageControl.bounds = CGRectMake(0, 0, 150, 50);
    pageControl.center = CGPointMake(scrollWdith * 0.5, scrollHight - 50);
    //设置页数
    pageControl.numberOfPages = kCount;
    //当前选中页码对应控制器的颜色
    pageControl.currentPageIndicatorTintColor = [UIColor redColor];
    //其他控制器的颜色
    pageControl.pageIndicatorTintColor = [UIColor blackColor];
    //监听pageControl事件
    [pageControl addTarget:self action:@selector(pageChanged:) forControlEvents:UIControlEventValueChanged];

    //添加控制器
    [self.view addSubview: pageControl];

    self._pageControl = pageControl;

    //设置代理
    scrollView.delegate = self;
    //不需要弹簧效果
    scrollView.bounces = NO;

}
#pragma mark -滚动代理:减速完毕后调用(停止了)
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    CGFloat offset = scrollView.contentOffset.x;   //当前x轴方向上滚动了多少
    int pageNum = offset/scrollView.frame.size.width;
    //设置页码
    self._pageControl.currentPage = pageNum;
}
#pragma mark pageControl值变化时调用
-(void) pageChanged{
    CGFloat offsetX = self._pageControl.currentPage * self.view.frame.size.width;
    [UIView beginAnimations:nil context:nil];
    self._scrollView.contentOffset = CGPointMake(offsetX, 0);
    [UIView commitAnimations];
}
@end

10. UITableView( android ListView GridView ExpandListView)

10.1 数据源方法

TableView相当于ListView,设置数据源需要遵循UITableViewDataSource协议,相当于BaseAdapter,下面是协议的所有接口:

@protocol UITableViewDataSource<NSObject>
@required   必须实现的
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;   // 第section组有多少行数据
// 返回每一行显示的具体数据View(相当于getView()方法)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
@optional  选择实现的
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;  // 一共有多少组数据(如果没有实现,默认为1)
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; // 分组头部标题
- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; // 分组尾部标题
// Individual rows can opt out of having the -editing property set for them. If not implemented, all rows are assumed to be editable.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
// Moving/reordering
// Allows the reorder accessory view to optionally be shown for a particular row. By default, the reorder control will be shown only if the datasource implements -tableView:moveRowAtIndexPath:toIndexPath:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
//索引(e.g. "ABCD...Z#")
- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView __TVOS_PROHIBITED;
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index __TVOS_PROHIBITED;  // tell table which section corresponds to section title/index (e.g. "B",1))
// Data manipulation - insert and delete support
// After a row has the minus or plus button invoked (based on the UITableViewCellEditingStyle for the cell), the dataSource must commit the change
// Not called for edit actions using UITableViewRowAction - the action's handler will be invoked instead
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
// Data manipulation - reorder / moving support
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
@end

10.2 代理 UITableViewDelegate

// 返回条目高度(可以根据不同的行号返回不同的高度)
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
//  选中某一行的时候调用(点击)
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
// 取消选中某一行
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath

10.3 常用属性和方法

10.4 多组数据

@interface ViewController ()
     @property (nonatomic, strong) NSArray *gd;
     @property (nonatomic, strong) NSArray *hn;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.gd = @[@"广州", @"东莞", @"惠州"];
    self.hn = @[@"常德", @"长沙", @"湘潭", @"株洲", @"岳阳", @"湘西自治州"];
}
#pragma mark - 数据源方法
#pragma mark - 1、一共多少组数据
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 2;   //广东、湖南
}
#pragma mark - 2、第section组有多少行数据
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
   return section==0?self.gd.count:self.hn.count;
}
#pragma mark - 3、返回每一行显示的具体数据
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    // 组 indexPath.section
    // 列 indexPath.row
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
    NSString *city = nil;

    if(indexPath.section == 0){
        city = self.gd[indexPath.row];
    }else {
        city = self.hn[indexPath.row];
    }
    //设置右边箭头样式
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    //设置cell上面显示的文本数据
    cell.textLabel.text = city;
    return cell;
}
#pragma mark - 4、 第section组的header标题
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    return section == 0? @"广州" : @"湖南";
}
#pragma mark - 5、 第section组的尾部标题
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
    return section == 0? @"广东很多帅哥": @"湖南很多美女";
}
#pragma mark- 6、 索引,通讯录效果,是按照分组而不是拼音首字母的索引
- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView __TVOS_PROHIBITED{
    return @[@"广州", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南", @"湖南"];
}

#pragma mark- UITableView代理方法
#pragma mark- 1、 返回某一行的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 70;
}
#pragma mark- 2、 选中某一行的时候调用(点击)
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    NSString *city = indexPath.section == 0? self.gd[indexPath.row] : self.hn[indexPath.row];
    //弹出对话框修改地名
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"地名" message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    //设置alertview样式
    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    //取出文本输入框
    [alert textFieldAtIndex:0].text = city;
    alert.tag = 1;
    //显示对话框
    [alert show];
}

#pragma mark- UIAlertView代理方法
#pragma mark- 对话框按钮点击
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex NS_DEPRECATED_IOS(2_0, 9_0){
    if(buttonIndex == 1){
        //点击了确定按钮
        //取得输入框文本
        NSString *city = [alertView textFieldAtIndex:0].text;
        NSString *old = self.gd[0];
        old = [NSString stringWithFormat:@"%@", city];
        //刷新UITableView数据,相当于android 的 adaptert.notifyDatesetChanged()
        //刷新所有数据
//        [self.tableView reloadData];
        //局部刷新
        NSIndexPath *path = [NSIndexPath indexPathForRow:alertView.tag inSection:0];
        [self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationLeft];
    }
}
@end

10.5 单组数据(ListView效果)

数据源返回分组数量的方法返回值为1就能实现单组效果

UITableViewCell系统样式:



条目右边箭头样式:

10.6 性能优化

  • 复用Cell

    Android的ListView在性能优化的时候复用convertView,这样getView方法不用每次加载创建条目View;iOS中UITableView的数据源方法cellForRowAtIndexPath中同样也可以复用缓存中的cell
      #pragma mark 每当有一个cell进入视野范围内就会调用,返回当前这行显示的cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 0.用static修饰的局部变量,只会初始化一次< # # >
    static NSString *ID = @"Cell";

    // 1.拿到一个标识先去缓存池中查找对应的Cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    // 2.如果缓存池中没有,才需要传入一个标识创建新的Cell
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }

    // 3.覆盖数据
    cell.textLabel.text = [NSString stringWithFormat:@" fdsfdsf-%d", indexPath.row];

    return cell;
}
  • 用户代码提醒

    Xcode中有很多系统自带的代码块,只需要拖动到编辑器中,就能自动生成代码,这样可以避免写很多重复代码,方便编程;也可以自定义用户代码块,比如上面复用Cell的模板方法,选中代码后拖动到右下角代码块中即可。

10.7 编辑模式

  • 删除\添加

    开启编辑模式:
 // 开启编辑模式
    //self.tableView.editing = YES;
    //[self.tableView setEditing:YES];
    // 带有动画效果
    [self.tableView setEditing:! edt animated:YES];

下面方法的返回值决定编辑模式是添加还是删除:

#pragma mark - 代理方法
#pragma mark 当tableview开启编辑模式就会调用
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //return indexPath.row%2 ? UITableViewCellEditingStyleDelete : UITableViewCellEditingStyleInsert;
    return tableView.tag;
}

实现数据源的方法删除或添加数据:

#pragma mark 提交编辑操作(点击了"删除"或者"+"按钮)时调用
// 实现了这个方法,就有左划删除功能
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle  forRowAtIndexPath:(NSIndexPath *)indexPath
{
    //NSLog(@"------commit---%d", indexPath.row);

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // 删除
        // 1.更改数据(删除本行的数据)
        [self.mydata removeObjectAtIndex:indexPath.row];

        // 2.刷新UI界面
        //[tableView reloadData];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
    } else {
        // 添加

        // 1.更改数据(添加数据)
        // [self.mydata addObject:@" hahahhahah"];添加到最后面去了
        // 插入数据到本行的后面
        [self.mydata insertObject:@"新添加的数据...." atIndex:indexPath.row + 1];

        // 2.刷新UI界面
        //[tableView reloadData];

        // 刷新指定行(个数不变)
        //[tableView reloadRowsAtIndexPaths:<#(NSArray *)#> withRowAnimation:<#(UITableViewRowAnimation)#>];
        // 删除指定行
        //[tableView deleteRowsAtIndexPaths:<#(NSArray *)#> withRowAnimation:<#(UITableViewRowAnimation)#>];
        // 插入新的行

        NSIndexPath *newPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0];
        [tableView insertRowsAtIndexPaths:@[newPath] withRowAnimation:UITableViewRowAnimationTop];
    }

}
  • 排序

    如果实现了数据源UITableViewDataSource的moveRowAtIndexPath方法,就会有排序拖动功能,但这只是界面表面的变化,数据顺序并没有变,所以在这个方法中,需要改变数据顺序。
#pragma mark 如果实现了这个方法, 就会有排序功能
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    // 取出即将要删除的数据
    NSString *data = self.mydata[sourceIndexPath.row];

    // 删除需要移动的那一行
    [self.mydata removeObject:data];

    // 插入之前删除的数据
    [self.mydata insertObject:data atIndex:destinationIndexPath.row];
}
  • 4个刷新UI界面的方法

    添加新的行:

    [tableView insertRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationTop];

    删除指定的行:

    [tableView deleteRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationTop]

    局部刷新指定的行:

    [tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationTop]

    整体刷新所有的行:

    [tableView reloadData]

10.8 自定义Cell

  • 步骤:

    ①、新建xid来描述Cell(拖一个UITableViewCell设置宽高以及identify);

    ②、实现数据源和代理方法,返回数据和Cell的高度(heightForRowAtIndexPath );

    ③、拿到Cell中的子控件绑定数据(根据tag);

    ④、拿到按钮绑定监听器(根据事件取得事件点对应的行号)
#pragma mark 每当有一个cell进入视野范围内就会调用,返回当前这行显示的cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 0.用static修饰的局部变量,只会初始化一次
    static NSString *ID = @"Cell";

    // 1.拿到一个标识先去缓存池中查找对应的Cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    // 2.如果缓存池中没有,才需要传入一个标识创建新的Cell
    if (cell == nil) {
        // 通过 xib文件来加载cell
        NSBundle *bundle = [NSBundle mainBundle];
        NSArray * objs = [bundle loadNibNamed:@"BookCell" owner:nil options:nil];
        cell = [ objs lastObject];

        // 绑定监听器
        UIButton *collect  = (UIButton *)[cell viewWithTag:3];
        [collect addTarget:self action:@selector(collectBook:event:) forControlEvents:UIControlEventTouchUpInside];
    }

    //cell.tag = indexPath.row + 1000;

    // 3.覆盖数据
    // 3.1 取出book对象
    Book *book = self.books[indexPath.row];
    // 3.2 设置名称
    UILabel *nameLabel = (UILabel *)[cell viewWithTag:1];
    nameLabel.text = book.name;

    return cell;
}
  • cell中的按钮添加点击事件

    通过点击事件点的位置,确定cell的索引:
// 得到触摸事件对象 --->  得到触摸点  ---> 得到触摸点在UITableView中的位置 ---> 得到触摸点在UITableView中的行号
- (void)collectBook:(UIButton *) btn event:(UIEvent *)event
{
    //NSLog(@"----%@", event);
    UITableView *tableView = (UITableView *)self.view;

    // 获取所有的触摸点(UITouch对象,如果是单点触碰,就只有1个UITouch)
    NSSet *touches = [event allTouches];

    // 一个UITouch对象对应一根手指
    UITouch *touch = [touches anyObject];

    // 获取触摸点在UITableView上面的的位置
    CGPoint position = [touch locationInView:tableView];

    // 根据触摸位置 得到 对应的行号
    NSIndexPath *indexPath = [tableView indexPathForRowAtPoint:position];
    //NSLog(@"%d", indexPath.row);

    Book *book = self.books[indexPath.row];
    NSLog(@"%@", book.name);
}
  • Cell属性封装:

    根据tag找控件(android根据id找控件),tag太多不好管理,效率不高,如果控件太多代码量大:

    定义一个类继承UITableViewCell,xid指向这个类,子控件作为此类的属性即可,创建Cell时用这个类接受:

10.9 九宫格

iOS中没有Android中的GridView,九宫格是由UITableView实现的,自定义Cell,每一行Cell中放入numClunk(多少列) 个按钮。

10.10 qq联系人列表

iOS中没有Android中的ExpandListView,如果需要实现分组展开合并功能,只需要控制返回那个分组返回的行数,行数为0就是合并了。

  • 自定义分组标题
#pragma mark 第section组对应的标题
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    HeaderView *titleView = [HeaderView buttonWithType:UIButtonTypeCustom];

    // 设置标题内容
    NSDictionary *dict = self.allFriends[section];
    [titleView setTitle:dict[@"group"] forState:UIControlStateNormal];

    // 设置标题颜色
    [titleView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

    // 设置背景颜色
    [titleView setBackgroundColor:[UIColor grayColor]];

    // 设置按钮的tag为组号
    titleView.tag = section;

    // 监听标题点击
    [titleView addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];

    // 取出第section组的状态
    int result = [self.status[@(section)] intValue];
    // 对状态进行取反
    if (result == 0) {
        titleView.imageView.transform = CGAffineTransformIdentity;
    } else {
        titleView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
    }

    return titleView;
}
  • 合并展开分组
#pragma mark - 监听标题点击
- (void)titleClick:(UIButton *)btn {
    // 取出标题按钮对应的组号
    int section = btn.tag;

    // 取出第section组的状态
    int result = [self.status[@(section)] intValue];

    // 对状态进行取反
    if (result == 0) {
        [self.status setObject:@1 forKey:@(section)];
    } else {
        [self.status setObject:@0 forKey:@(section)];
    }

    // 刷新数据(会重新给数据源发送消息)
    [self.tableView reloadData];
}

//- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
//{
//    // 1.获取这组对应的字典数据
//    NSDictionary *dict = self.allFriends[section];
//
//    return dict[@"group"];
//}

#pragma mark 每一组中有多少行数据
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // 取出第section组对应的状态
    int result = [self.status[@(section)] intValue];

    if (result == 0) { // 合并状态
        return 0;
    } else { // 展开状态
        // 1.先获取这组对应的数据
        NSDictionary *group = self.allFriends[section];
        // 2.获取这组里面的好友
        NSArray *friends = group[@"friends"];
        return friends.count;
    }
}

iOS常见控件的基本使用的更多相关文章

  1. android 仿ios开关控件

    ios一些控件还是挺美丽的,可是对android程序猿来说可能比較苦逼,由于ios一些看起来简单的效果对android来说可能就没那么简单了,可是没办法非常多产品都是拿ios的一些控件叫android ...

  2. 79.iOS 设备的UI规范和iOS各控件默认高度

    iOS设备的UI 规范 iPhone界面尺寸 iPhone图标尺寸 iPad的设计尺寸 iPad图标尺寸 iPhone设备尺寸分辨率比例 iPhone各设备 launch image iOS 各种控件 ...

  3. JS调用Android、Ios原生控件

    在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...

  4. 初识IOS,Label控件的应用。

    初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...

  5. IOS—UITextFiled控件详解

    IOS—UITextFiled控件详解 //初始化textfield并设置位置及大小 UITextField *text = [[UITextField alloc]initWithFrame:CGR ...

  6. [iOS基础控件 - 5.5] 代理设计模式 (基于”APP列表"练习)

    A.概述      在"[iOS基础控件 - 4.4] APP列表 进一步封装,初见MVC模式”上进一步改进,给“下载”按钮加上效果.功能      1.按钮点击后,显示为“已下载”,并且不 ...

  7. iOS 各种控件默认高度

    1.状态栏 状态栏一般高度为20像素,在打手机或者显示消息时会放大到40像素高,注意,两倍高度的状态栏在好像只能在纵向的模式下使用.如下图   用户可以隐藏状态栏,也可以将状态栏设置为灰色,黑色或者半 ...

  8. (转)iOS 各种控件默认高度(图示)

    1.状态栏 状态栏一般高度为20像素,在打手机或者显示消息时会放大到40像素高,注意,两倍高度的状态栏在好像只能在纵向的模式下使用.如下图 用户可以隐藏状态栏,也可以将状态栏设置为灰色,黑色或者半透明 ...

  9. C#中WindowsForm常见控件的运用

    C#中WindowsForm常见控件的运用 -- 1.button(曹操,贡天子以令不臣): 属性;text:我们经常可以看见将按钮命名为“登入”,在其属性面板里面编辑text即可:如下图:      ...

随机推荐

  1. 再深刻理解下web3.js中estimateGas如何计算智能合约消耗的gas量

    我们可使用web3.js框架的estimateGas函数获得一个以太坊智能合约的Gas估计值 ,通过执行一个消息调用或交易,该消息调用或交易直接在节点的VM中执行,并未在区块链中确认,函数会返回估算使 ...

  2. Linear Regression with Scikit Learn

    Before you read  This is a demo or practice about how to use Simple-Linear-Regression in scikit-lear ...

  3. [SDOI 2011]消耗战

    Description 题库链接 给你一棵 \(n\) 个节点根节点为 \(1\) 的有根树,有边权. \(m\) 次询问,每次给出 \(k_i\) 个关键点.询问切断一些边,使这些点到根节点不连通, ...

  4. [UOJ UNR#2 黎明前的巧克力]

    来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 很奇妙的一道题 首先不难发现一个暴力做法,就是f[i]表示异或和为i的答案数,每次FWT上一个F数组,其中F[0]=1,F[ai]=2 ...

  5. 2017ACM/ICPC广西邀请赛-重现赛 1010.Query on A Tree

    Problem Description Monkey A lives on a tree, he always plays on this tree. One day, monkey A learne ...

  6. ubuntu16.04安装eclipse后启动栏图标为问号

    ubuntu创建eclipse快捷方式图标. cd /usr/share/applications sudo touch eclipse.desktop sudo gedit eclipse.desk ...

  7. 【转】Java方向如何准备技术面试答案(汇总版)

    本文转载自:“Java团长”公众号 1.面向对象和面向过程的区别 面向过程优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机.嵌入式开发.Linux/Unix等一般采 ...

  8. PAT甲级真题打卡:1001.A+B Format

    题目: Calculate a + b and output the sum in standard format -- that is, the digits must be separated i ...

  9. Java正则过滤

    import java.util.regex.Matcher; import java.util.regex.Pattern; public class LongStringtonumber { pu ...

  10. Echarts 地图添加自定义区域

    使用 Echarts 生成地图时,如果需要添加一些自定义区域,该怎么做呢?请看下面示例. 生成原始地图 index.hmtl 引入 Jquery 和 Echart <!DOCTYPE html& ...