IOS開發基礎—簡單的qq表情排列app

dqw18037發表於2015-05-07

作者宣告

因個人能力問題,文中不免有錯誤之處,歡迎各位讀者交流,批評,指正!

摘要

本文通過一個例項:將qq表情按不同的列排序,並實現表情新增功能,學習控制元件segment的基本用法。

例項

viewController h程式碼

//
//  ViewController.h
//  簡單的表情排列app
//
//  Created by dqw on 15/5/7.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UIView *iconsView;

@property (weak, nonatomic) IBOutlet UISegmentedControl *segment;

- (IBAction)setColumns:(UISegmentedControl *)sender;


@end

viewController m程式碼

//
//  ViewController.m
//  簡單的表情排列app
//
//  Created by dqw on 15/5/7.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

{
    // 定義供多個方法使用的成員變數。
    NSArray *_iconViews;
    CGFloat _width;
    CGFloat _height;
    CGFloat _x;
    CGFloat _y;
    NSUInteger _count;  // 表情圖片的個數。
    int _n; // 新增的表情個數。

}

@end

@implementation ViewController

#pragma mark 1. 初始化載入表情。
- (void)viewDidLoad {

    [super viewDidLoad];

    // 初始化。
    _n = 0;

    // 給_width和_height賦值。
     UIImage *icon = [UIImage imageNamed:@"0.png"];

    _width = icon.size.width;

    _height = icon.size.height;

    // 定義變數。
    NSString *iconName;
    UIImageView *iconView;

    for (int i = 0; i < 10; i++) {

        // 建立圖片例項。
        iconName = [NSString stringWithFormat:@"%d.png",i];

        UIImage *icon = [UIImage imageNamed:iconName];

        // 建立圖片檢視。        
        iconView = [[UIImageView alloc]init];

        // 定義各圖片控制元件的位置。
        _x = (_iconsView.frame.size.width - _width * 2) * 0.5 + _width * (i % 2);

        _y = _height * (i / 2);

        // 設定圖片控制元件
        iconView.frame = CGRectMake(_x, _y,_width,_height);

        iconView.image = icon;

        if (i == 9) {

#pragma mark 重點:uiimageview不能呼叫addtargetxx方法。
            // 新增uicontrol型別的控制元件,因為uiimageview型別的控制元件不可以新增監聽事件。addtatget不是uiview的方法,而是其子類uicontrol的方法。
            UIButton *addBut = [[UIButton alloc]init];

            addBut.frame = CGRectMake(_x, _y,_width,_height);

            [addBut setBackgroundImage:icon forState:UIControlStateNormal];

            [_iconsView addSubview:addBut];
        }
        else{
        // 新增圖片控制元件。
            [_iconsView addSubview:iconView];
        }

    }

    // 提取圖片框中的所有子控制元件到陣列內。注意體會:@property(nonatomic,readonly,copy) NSArray *subviews;
    _iconViews = _iconsView.subviews;

    _count = _iconViews.count;

#pragma mark 為最後一個button控制元件新增監聽事件。
    // 為最後一個控制元件新增監聽事件。
    [_iconViews[_count -1] addTarget:self action:@selector(addIcon) forControlEvents:UIControlEventTouchUpInside];
}

#pragma mark 2. 定義監聽事件呼叫的新增表情方法。
- (void)addIcon{

    // 更新_count數值。
    _iconViews = _iconsView.subviews;

    _count = _iconViews.count;

#pragma mark 重點2:不能通過陣列元素來訪問frame變數。
    // 因為不能通過陣列元素得到frame屬性。所以通過一個相同型別的指標temp來得到其frame屬性。
    UIImageView *temp =  _iconViews[_count -1];

    UIImageView *temp1 = [[UIImageView alloc]init];

    // 深刻體會。
    temp1.frame = temp.frame;

    NSString *iconName = [NSString stringWithFormat:@"%d.png",(_n++ % 9)];

    temp1.image = [UIImage imageNamed:iconName];

#pragma mark 重點3:insert  below 。
    // 在最後一個元素前面插入新元素,注意用的是below。
    [_iconsView insertSubview:temp1 belowSubview:_iconViews[_count - 1]];

    // 插入新元素後更新_count值。
    _iconViews = _iconsView.subviews;

    int index  = _iconViews.count -1;

    // 為了得到列數,引入了segment成員變數。
    int column = _segment.selectedSegmentIndex + 2 ;

    // 更改最後一個元素的位置。
    _x = (_iconsView.frame.size.width - _width * column) * 0.5 + _width * (index % column);

    _y = _height * (index / column);

    temp.frame = CGRectMake(_x, _y, _width, _height);

}

#pragma mark 3. 按列排序。
- (IBAction)setColumns:(UISegmentedControl *)sender{

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1.0];

    // 獲取列數。
    int column = sender.selectedSegmentIndex + 2;

    // 更新_count。
    _iconViews = _iconsView.subviews;

    _count = _iconViews.count;

#pragma mark 重點3:不能通過陣列元素來訪問frame變數。
    // 此處需注意:不能通過陣列訪問subview的frame成員變數(即_iconView[i].frame 是錯誤的表達,編譯不通過),所以要新建一個臨時的UIImageView temp 來作為過渡。個人認為:可能是因為_iconView是個不可變陣列.但是把其中的元素提取出來後,更改其屬性,實際的元素屬性的確被更改了,這是不是代表著該陣列是深複製的不可變陣列(uiview的subviews變數是用copy修飾的),但是其中的元素時淺複製,所以單獨更改後,真實的元素屬性也被更改了。雖然temp是通過賦值得到的元素,但是temp和xx[]都是指標,所以都指向的時同樣的元素。
#pragma mark 疑問1 subviews copy修飾??
    // @property(nonatomic,readonly,copy) NSArray *subviews;還不是理解?

    UIImageView *temp;

    for (int i = 0; i < _count; i++) {

        // 對應temp。
        temp = _iconViews[i];

        // 讓圖片位於左右的中間,注意取餘數和取商的用法。
        _x = (_iconsView.frame.size.width - _width * column) * 0.5 + _width * (i % column);

        _y = _height * (i / column);

        temp.frame= CGRectMake(_x, _y, _width, _height);
    }

    [UIView commitAnimations];

}
@end

重點 難點 注意點

  1. uiimageview不能呼叫addtarget方法,將最後的加號圖片設定為uibutton型別。
  2. 在uiimageview中最後一個subview前面插入subview ,是用的below,而不是above。
  3. 不能通過陣列訪問subview的frame成員變數(即_iconView[i].frame 是錯誤的表達,編譯不通過),所以要新建一個臨時的UIImageView temp 來作為過渡。個人認為:可能是因為_iconView是個不可變陣列.但是把其中的元素提取出來後,更改其屬性,實際的元素屬性的確被更改了,這是不是代表著該陣列是深複製的不可變陣列(uiview的subviews變數是用copy修飾的),但是其中的元素時淺複製,所以單獨更改後,真實的元素屬性也被更改了。雖然temp是通過賦值得到的元素,但是temp和xx[]都是指標,所以都指向的時同樣的元素。
  4. 既然是排列,類似於矩陣,為了得到其行數和列數,用取餘數和取商是個很好的方法。

疑問

  1. @property(nonatomic,readonly,copy) NSArray *subviews;還不是理解?其中的copy??

待完善的內容

  1. 更深入瞭解一下segment的用法。

相關文章