iOS开发教程之微博骨架搭建

2020-01-12 13:29:54王振洲

Dock.h


//
// Dock.h
// 20_帅哥no微博
//
// Created by beyond on 14-8-3.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// Dock就是主控制器下面的一条bar,它里面是由一个个按钮DockBtn组成

#import <UIKit/UIKit.h>
@class DockBtn;
@interface Dock : UIView
// 添加一个item到Dock(View),参数是图标名,和要显示 的标题 ,以及对应的子控制器的类名

- (void)addDockBtnWithIconName:(NSString *)iconName title:(NSString *)title viewControllerClassName:(NSString *)viewControllerClassName;

// 当Dock里面的某一个按钮被点击了的时候,调用代码块,处理相应的点击事件
@property (copy,nonatomic) void(^btnClickBlock)(DockBtn *);



// 自定义方法,通过代码决定哪一个dockBtn被点击了,参数是 Dock栏里面的那个将要被点击的按钮的索引
- (void)setDockBtnClickedAtIndex:(int)index;
@end

Dock.m


//
// Dock.m
// 20_帅哥no微博
//
// Created by beyond on 14-8-3.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 这个就是主控制器下面那一栏,Tabbar,也叫Dock,里面有五个按钮,分别是首页,我,消息,广场,更多

#import "Dock.h"
#import "DockBtn.h"

@interface Dock()
{

  // 当前选中了那个dockBtn
  DockBtn *_currentDockBtn;
}
@end

@implementation Dock
// init方法内部会调用initWithFramne
- (id)initWithFrame:(CGRect)frame
{
  self = [super initWithFrame:frame];
  if (self) {
    // 固有固定属性,设置Dock背景颜色(分类方法,使用imageName就可进行平铺)
    self.backgroundColor = [UIColor colorWithPatternImageNamed:@"tabbar_background.png"];
  }
  return self;
}

// 给外部提供一个接口,添加一个DockBtn(按钮)到Dock(View),参数是图标名,和要显示 的标题,以及对应的子控制器的类名
- (void)addDockBtnWithIconName:(NSString *)iconName title:(NSString *)title viewControllerClassName:(NSString *)viewControllerClassName
{
  // 1.创建dock里面的按钮,并添加到dock里面
  DockBtn *dockBtn = [DockBtn buttonWithType:UIButtonTypeCustom];
  [self addSubview:dockBtn];
  
  // 2.设置dockBtn正常状态下显示 的文字
  [dockBtn setTitle:title forState:UIControlStateNormal];
  
  // 3.分类方法,设置按钮正常和选中状态下的图片,返回图片尺寸
  [dockBtn setBtnImgForNormalAndSelectedWithName:iconName];
  
  // 4.设置dockBtn对应点击后,要实例化的子控制器的类名
  [dockBtn setViewControllerClassName:viewControllerClassName];
  
  // 5.监听点击,只要按下就响应,(事件先传递给Dock的方法,Dock的方法中再通过调用属性block代码块,从而调用到主控制器里面的代码,原因是:在主控制器里面实例化的dock,在Dock里面才实例化的dockBtn,因此,主控制器并不知道dockItem的存在)
  [dockBtn addTarget:self action:@selector(dockBtnClick:) forControlEvents:UIControlEventTouchDown];
  
  // 6.遍历设置Dock里面所有按钮的frame (使之平均分布)
  [self setDockBtnFrames];
}

// 遍历设置Dock里面所有按钮的frame (使之平均分布)
- (void)setDockBtnFrames
{
  // 1,获取dock里面所有的按钮个数
  int dockBtnNum = self.subviews.count;
  
  // 2,根据dock中,当前当前有多少个DockBtn,计算出每个dockBtn的宽度(self是dock,320*44)
  CGFloat dockBtnWidth = self.frame.size.width / dockBtnNum;
  CGFloat dockBtnHeight = self.frame.size.height;
  
  for (int i = 0; i < dockBtnNum; i++) {
    // 1.逐个取出子控件
    DockBtn *btn = self.subviews[i];
    
    // 2.根据索引 计算它的x
    btn.frame = CGRectMake(i * dockBtnWidth, 0, dockBtnWidth, dockBtnHeight);
    
    // 3.初始化的时候,将第0个btn(即首页)选中
    if (i == 0) {
      btn.selected = YES;
      // 最重要的是,将选中的,置为当前的按钮,用成员变量记住,当点击dock上button的时候,先将current置为未选中,然后就被点击的按钮选中,最后最重要的是,将被点击的按钮重新置为当前 的按钮,用成员变量记住
      _currentDockBtn = btn;
    }
    
    // 4.因为点击dock里面的按钮的时候,要知道点击了哪一个按钮,所以给每个按钮绑定一个tag,作为它的索引
    btn.tag = i;
  }
}

// 最重要的是,当点击dock上button的时候,先将current置为未选中,然后就被点击的按钮选中,最后最重要的是,将被点击的按钮重新置为当前 的按钮,用成员变量记住
- (void)dockBtnClick:(DockBtn *)btn
{
  // 1.让当前的btn取消选中
  _currentDockBtn.selected = NO;
  
  // 2.让新的btn选中
  btn.selected = YES;
  
  // 3.最后,让新的btn变为当前选中btn
  _currentDockBtn = btn;
  
  // 4.调用block,即主控制中传递过来的代码块,目的是处理点击之后的实例化对应的子控制器
  if (_btnClickBlock) {
    // 将参数 DockBtn传递过去,给主控制器,它里面成员变量记住了它对应的控制器的类名
    _btnClickBlock(btn);
  }
}



// 自定义方法,通过代码决定哪一个dockBtn被点击了,参数是 Dock栏里面的那个将要被点击的按钮的索引
- (void)setDockBtnClickedAtIndex:(int)index
{
  // 1.robust判断
  if (index < 0 || index >= self.subviews.count) return;
  
  // 2.通过索引 拿到对应的DockBtn viewWithTag也行
  DockBtn *btn = self.subviews[index];
  
  // 3.手动调用下面方法,相当于用户用手点击了dock里面对应的按钮
  [self dockBtnClick:btn];
}
@end