《iOS6 application development》学习之路:No.3: 自定义选择器

简介:

先看下程序跑起来的样子吧,没有做任何,任何界面上的优化,所以请忽视丑陋的页面。

总共就两个,第一个页面是inital页面,中间一个label用来显示用户做的不同选择,下方是一个放在tool bar里面的button,用户点击后可以进行两个页面的切换。第2个页面总共有3个空间,最上端是一个自定义的pick view,两列,第一列显示动物的图片,第二列显示动物的叫声。中间是一个label,最下端是一个按钮,点击按钮后用来返回上一个页面。

因为教材中是按照功能拆分了一块一块讲解的,所以这次分别把2个页面的最终接口和实现文件整体来看,也算是给自己做个回顾和总结。

前提:

需要在Xcode的项目导航器中新增一个类,名字叫AnimalChooserViewController。然后将这个类和我们新增加的页面关联起来,从类的名字也能看出来是第2个页面了。记得把两个页面在IB中的名字分别改成initial和Anima Chooser,这样做的好处就不多说了。

还要把一些资源文件拖进来,主要是7个动物的图片,这些都可以在这本书的网站上下载到。好了,下面就是4个重头戏了。

先来说initial页面的接口文件:ViewControll.h

#import <UIKit/UIKit.h>
#import "AnimalChooserViewController.h"

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *outputLabel;

- (IBAction)showAnimalChosser:(id)sender;

- (void) displayAnimal:(NSString* )chosenAnimal
             withSound:(NSString* )chosenSound
         fromComponent:(NSString* )chosenComponent;

@property (nonatomic) Boolean animalChooserVivible;

@end

很简单有没有,

这里面我们要import进来我们新建的那个类,因为要做交互啊。一个控件 outputLabel 和函数 showAnimalChosser 都是很简单的,通过IB里面鼠标拖动来添加,这些都再简单不过了。我们需要一个新的property: animalChooserVisibile来存储第2个场景的当前可见性。同时还有一个自定义的函数,displayAnimal,有3个参数:chosenAnima、chosenSound和chosenComponent,这个函数是用来接收第2个场景传递过来的信息并显示在label上的。

下面上ViewControll.m文件:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)showAnimalChosser:(id)sender {
    if(self.animalChooserVivible !=YES){
        [self performSegueWithIdentifier:@"toAnimalChooser" sender:sender]; //preform the animal chooser sence
        self.animalChooserVivible = YES;
    }
}

- (void) displayAnimal:(NSString *)chosenAnimal withSound:(NSString *)chosenSound fromComponent:(NSString *)chosenComponent{
    NSString* animalSoundString;
    animalSoundString = [[NSString alloc]
                         initWithFormat:@"You changed %@ (%@ and the sound %@)",
                         chosenComponent,chosenAnimal,chosenSound];
    self.outputLabel.text = animalSoundString;
}


- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    ((AnimalChooserViewController *) segue.destinationViewController).delegate = self;
}

@end

实现文件主要完成3个函数:showAnimalChooser是用户点击toolbar上的按钮时进行的函数:判断当第2个场景可显示时,进行切换。注意,一定要在IB中把场景切换命名为toAnimaChooser,否则是无法完成手动切换的。

displayAnimal函数根绝接受到的3个参数,修改label的文字内容内容,这个函数会在第2个界面上点击Done之后被调用。

prepareForSeque函数:为了使用属性delegate来访问initial场景,我们马上将看到在AnimalChooserViewController的接口文件中会加入属性,所以在这里调用此函数来设置initial场景的属性。

AnimalChooserViewController.h:

#import <UIKit/UIKit.h>
#import "ViewController.h"
@class ViewController;

@interface AnimalChooserViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>

@property (weak, nonatomic) id delegate;

- (IBAction)dismissAnimalChosser:(id)sender;
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
@end

@interface AnimalChooserViewController(){
    NSArray* _animalNames;
    NSArray* _animalSounds;
    NSArray* _animalImages;
}
@end
看到了新添的属性 id delegate,用来访问initial场景。

一个函数: dismissAnimalChooser,当用户点击DONE按钮时,退回到initial界面。

这里需要将3个数组声名为私有变量,OC的私有变量是这样声名的,记一下了。

为什么要声名3个数组是为了更好的现实动物的名字,因为原始的图片是带了.png的,我们当然不希望把这个现实出来,所以要重新映射一下名字,以及声音和图片。

注意到在interface AnimalChooserViewController: UIViewController 后面还加上了  <UIPickerViewDataSource, UIPickerViewDelegate>,作用是为了调用自定义选择器的几个函数。在实现文件中会用到的。

AnimalChooserViewController.m:


#import "AnimalChooserViewController.h"
#define kComponentCount 2           //define how many columns will be performed in the pick view
#define kAnimalComponent 0          //the index for the first column
#define kSoundComponent 1           //index for the second column

@interface AnimalChooserViewController ()

@end

@implementation AnimalChooserViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    _animalNames = @[@"Mouse", @"Goose", @"Cat",@"Dog",@"Snake",@"Bear",@"Pig"];
    _animalSounds = @[@"Oink",@"Rawr",@"Ssss",@"Roof",@"Meow",@"Honk",@"Squeak"];
    _animalImages = @[
                      [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"mouse.png"]],
                      [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"goose.png"]],
                      [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cat.png"]],
                      [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dog.png"]],
                      [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"snake.png"]],
                      [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bear.png"]],
                      [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pig.png"]],
                      ];
}

- (void) viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    //Do any additional after view has been displayed
    
    ViewController* initialView;
    initialView = (ViewController*)self.delegate;
    [initialView displayAnimal:_animalNames[0] withSound:_animalSounds[0] fromComponent:@"nothing yet be chooosen"];
}


- (void)viewWillDisappear:(BOOL)animated{
    ((ViewController *)self.delegate).animalChooserVivible = NO;
}



- (NSInteger) numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return kComponentCount;
}

//founctions in the protocol "UIPickerViewDataSource"
- (NSInteger) pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    if(component == kAnimalComponent){
        return [_animalNames count];
    }else {
        return [_animalSounds count];
    }
}

//-----------------------------------------------------------------------//
// founctions in the protocol "UIPickerViewDelegate"
- (UIView* ) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
    if (component == kAnimalComponent){
        return _animalImages[row];
    } else {
        UILabel* soundLabel;
        soundLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 32)];
        soundLabel.backgroundColor = [UIColor clearColor];// make the Rect into the background, because the color is transparent
        soundLabel.text = _animalSounds[row];
        return soundLabel;
    }
}

//set the height of one single row
- (CGFloat) pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
    return 55.0;
}

//set the width of the diffenret column
- (CGFloat) pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{
    if(component == kAnimalComponent){
        return 75.0;
    }else {
        return 150.0;
    }
}

//after user selected one row
- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    ViewController* initialView;
    initialView = (ViewController* )self.delegate;
    
    if(component == kAnimalComponent){
        int chosenSound = [pickerView selectedRowInComponent:kSoundComponent];
        [initialView displayAnimal:_animalNames[row] withSound:_animalSounds[chosenSound] fromComponent:@"the Animal"];
    }
    else{
        int chosenAnimal = [pickerView selectedRowInComponent:kAnimalComponent];
        [initialView displayAnimal:_animalNames[chosenAnimal] withSound:_animalSounds[row] fromComponent:@"the Sound"];
    }
}

//-----------------------------------------------------------------------//




- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

- (IBAction)dismissAnimalChosser:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil]; // manual close this sence.
}
@end

实现文件有点长,不要急,分开来看行了。

首先#define了几个名称,我都用注释标出来了。

在ViewDidLoad函数中,初始化了3个私有数组,

viewDidAppear函数中,初始化界面,把选择器都设置成第0帐图片和第0个声音,然后文字设置成 nothing yet been chosen。其实就是默认的选择器状态。注意这里其实就已经调用了initial界面的函数, 如果用户没有做任何改变返回第一个界面,可以给用户正确的提示。

viewWillDisappear

将initial用到的属性设置成NO,

 numberOfComponentsInPickerView

是我们在头文件中看到了<>里面包含的协议里面的函数,这个方法返回选择器将显示几个组件,我们这里就两列,数字已经#define过了

//founctions in the protocol "UIPickerViewDataSource"

- (NSInteger) pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{

    if(component == kAnimalComponent){

        return [_animalNames count];

    }else {

        return [_animalSounds count];

    }

}


我标注出来了,在协议  datasource中有的方法,numberOfRowsInComponent,返回每个组件包含的元素数目。数组的数目可以用count函数得到。

// founctions in the protocol "UIPickerViewDelegate"
- (UIView* ) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
    if (component == kAnimalComponent){
        return _animalImages[row];
    } else {
        UILabel* soundLabel;
        soundLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 32)];
        soundLabel.backgroundColor = [UIColor clearColor];// make the Rect into the background, because the color is transparent
        soundLabel.text = _animalSounds[row];
        return soundLabel;
    }
}

//set the height of one single row
- (CGFloat) pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
    return 55.0;
}

//set the width of the diffenret column
- (CGFloat) pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{
    if(component == kAnimalComponent){
        return 75.0;
    }else {
        return 150.0;
    }
}

//after user selected one row
- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    ViewController* initialView;
    initialView = (ViewController* )self.delegate;
    
    if(component == kAnimalComponent){
        int chosenSound = [pickerView selectedRowInComponent:kSoundComponent];
        [initialView displayAnimal:_animalNames[row] withSound:_animalSounds[chosenSound] fromComponent:@"the Animal"];
    }
    else{
        int chosenAnimal = [pickerView selectedRowInComponent:kAnimalComponent];
        [initialView displayAnimal:_animalNames[chosenAnimal] withSound:_animalSounds[row] fromComponent:@"the Sound"];
    }
}

//-----------------------------------------------------------------------//

这几个函数都是DateViewDelegate协议中有的方法。当你在头文件中包含了这个协议,在接口文件中编译器会自动补全你想要写的函数的,good UE!

第1个函数给每个选择器元素提供自定义视图,这里手动动态添加了label,同时必须有2个的return值,否则XCode会提示你错误。这里注意到label的background用的时 clearColor,返回一个透明的颜色对象,否则矩形就不会融合到选择器视图的背景中。

第2个函数设置了每行的高度

第3个函数设置了不同列的宽度,这些数字都可以通过不断的纠错来达到你最满意的效果,话说回来可能是程序比较小,总感觉iOS的系统部署起来非常快,比android快多了。。。。

最后一个函数是在用户做出选择时的响应,其实就是给要传递给initial页面的3个参数附上正确的值。


实现文件的最后一个函数


- (IBAction)dismissAnimalChosser:(id)sender {

    [self dismissViewControllerAnimated:YES completion:nil]; // manual close this sence.

}

@end

因为是iPhone的版本,需要手工关闭场景,如果是iPad,因为弹出来的是个对话框,所以点击其他地方就可以关闭了,所以这个函数只有在iPhone上才需要用到。













目录
相关文章
|
3月前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户点击按钮时,按钮将从圆形变为椭圆形,颜色从蓝色渐变到绿色;释放按钮时,动画以相反方式恢复。通过UIView的动画方法和弹簧动画效果,实现平滑自然的过渡。
96 1
|
4月前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
【10月更文挑战第18天】本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户按下按钮时,按钮将从圆形变为椭圆形并从蓝色渐变为绿色;释放按钮时,动画恢复原状。通过UIView的动画方法和弹簧动画效果,实现平滑自然的动画过渡。
82 5
|
4月前
|
Swift iOS开发 UED
实现一个自定义的iOS动画效果
本文介绍如何使用Swift和UIKit在iOS应用中实现一个自定义按钮动画,当按钮被点击时,其颜色从蓝色渐变为绿色,形状从圆形变为椭圆形,释放后恢复原状。通过UIView动画方法实现这一效果,代码示例展示了动画的平滑过渡和状态切换,有助于提升应用的视觉体验和用户交互。
79 1
|
5月前
|
Swift iOS开发 UED
揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【9月更文挑战第5天】本文通过具体案例介绍如何在iOS应用中使用Swift与UIKit实现自定义按钮动画,当用户点击按钮时,按钮将从圆形变为椭圆形并从蓝色渐变到绿色,释放后恢复原状。文中详细展示了代码实现过程及动画平滑过渡的技巧,帮助读者提升应用的视觉体验与特色。
87 11
|
6月前
|
Swift iOS开发 UED
【绝妙创意】颠覆你的视觉体验!揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【8月更文挑战第13天】本文通过一个具体案例,介绍如何使用Swift与UIKit在iOS应用中创建独特的按钮动画效果。当按钮被按下时,其形状从圆形变化为椭圆形,颜色则从蓝色渐变为绿色;释放后,动画反向恢复原状。利用UIView动画方法及弹簧动画效果,实现了平滑自然的过渡。通过调整参数,开发者可以进一步优化动画体验,增强应用的互动性和视觉吸引力。
75 7
|
7月前
|
前端开发 开发工具 Swift
学习iOS开发的准备
准备学习iOS开发?确保有Mac和最新Xcode,先学好编程基础特别是Swift。利用Apple官方文档、在线课程和书籍作为资源。熟悉Xcode及Git,通过实践项目和开源代码积累经验。深研架构模式、核心框架和优化技巧。加入开发者社区,关注行业动态,持续学习。
68 1
|
9月前
|
iOS开发 UED
实现一个自定义的iOS动画效果
【4月更文挑战第9天】本文将详细介绍如何在iOS平台上实现一个自定义的动画效果。我们将通过使用Core Animation框架来实现这个动画效果,并展示如何在不同的场景中使用它。文章的目标是帮助读者理解如何使用Core Animation框架来创建自定义动画,并提供一个简单的示例代码。
80 1
|
安全 前端开发 Android开发
鸿蒙开发|鸿蒙系统的介绍(为什么要学习鸿蒙开发|鸿蒙系统的官方定义|鸿蒙和安卓、ios的对比)
鸿蒙开发学习是一项探索性的工作,旨在开发一个全场景分布式操作系统,覆盖所有设备,让消费者能够更方便、更直观地使用各种设备。
817 6
鸿蒙开发|鸿蒙系统的介绍(为什么要学习鸿蒙开发|鸿蒙系统的官方定义|鸿蒙和安卓、ios的对比)
|
iOS开发
iOS UIKit Dynamics Demo 学习地址列表
iOS UIKit Dynamics Demo 学习地址列表
66 0
|
API iOS开发
iOS 自定义转场动画 UIViewControllerTransitioning
iOS 自定义转场动画 UIViewControllerTransitioning
132 0

热门文章

最新文章

  • 1
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 2
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 3
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 4
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 6
    iOS8 中无需开源库的内置功能一览
  • 7
    iOS7应用开发7:自定义视图、手势操作
  • 8
    IOS小工具以及精彩的博客
  • 9
    Facebook SDK(iOS)初学讲解
  • 10
    iOS - Swift NSPoint 位置
  • 1
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    13
  • 2
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    28
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    34
  • 4
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    29
  • 5
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    23
  • 6
    uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
    143
  • 7
    【05】2025年1月首发完整版-篇幅较长-苹果app如何上架到app store完整流程·不借助第三方上架工具的情况下无需花钱但需仔细学习-优雅草央千澈详解关于APP签名以及分发-们最关心的一篇来了-IOS上架app
    235
  • 8
    app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
    90
  • 9
    深入探索iOS开发中的SwiftUI框架
    145
  • 10
    ios样式开关按钮jQuery插件
    60