Advertisement
  1. Code
  2. iOS SDK

Membuat sebuah aplikasi cuaca dengan ramalan-antarmuka pengguna

Scroll to top
Read Time: 28 min

() translation by (you can also view the original English article)

Dalam artikel terakhir dari seri ini, saya akan menunjukkan kepada Anda bagaimana untuk menciptakan user interface aplikasi cuaca kita. Berkat kerja Chris Carey, seorang kontributor tetap Vectortuts +, kami memiliki desain yang indah yang kita dapat bekerja dengan!


Pengenalan

Untuk desain aplikasi cuaca kita, saya berkolaborasi dengan Chris Carey, seorang kontributor tetap Vectortuts +. Chris dibuat desain yang indah yang bisa kita gunakan untuk membuat aplikasi antarmuka pengguna. Setelah Chris menyodorkan desain vektor ilustrasi, aku diiris karya seni dan siap untuk digunakan dalam proyek kami. Anda dapat menemukan karya seni irisan dalam file sumber dari artikel ini.

Create a Weather App with Forecast – User Interface - Chris Carey's Design Create a Weather App with Forecast – User Interface - Chris Carey's Design Create a Weather App with Forecast – User Interface - Chris Carey's Design
Gambar 1: Chris Carey desain

Karena customizability terbatas dari UIKit, kita akan harus membuat beberapa kompromi ketika mengimplementasikan Chris' desain. Hasil akhir, namun, akan terlihat sangat banyak seperti desain yang Chris ciptakan untuk kita. Menyesuaikan UIKit's UISwitch kelas, misalnya, sangat terbatas dan oleh karena itu kita akan menggunakan pendekatan yang berbeda untuk menerapkan pengaturan suhu. Chris digunakan dua font kustom untuk desain, Maven Pro dan misi Gothic. Meskipun iOS mendukung font kustom, kami hanya akan menggunakan font yang tersedia pada iOS.


1. pemberitahuan

Langkah 1: Membuat konstanta String

Bila cuaca Lihat controller menerima data cuaca dari API ramalan, lihat sendiri dan pandangan yang benar perlu diperbarui. Ini berarti bahwa kita perlu untuk memberitahu controller Lihat ramalan dan mengirimkannya data cuaca. Ada beberapa cara untuk memberitahu controller ramalan Lihat kejadian tersebut. Posting pemberitahuan menggunakan NSNotificationCenter adalah solusi yang paling sederhana dan memberi kita dengan fleksibilitas terbanyak. Kita dapat menggunakan solusi yang sama untuk memperbarui antarmuka pengguna setelah pengguna telah toggled pengaturan suhu. Dengan mengirimkan pemberitahuan, setiap objek yang tertarik dalam acara ini dapat mendaftarkan dirinya sendiri sebagai pengamat. Aku telah memperbarui MTConstants.h/.m untuk membuat string konstan untuk setiap pemberitahuan.

1
extern NSString * const MTRainWeatherDataDidChangeChangeNotification;
2
extern NSString * const MTRainTemperatureUnitDidChangeNotification;
1
NSString * const MTRainWeatherDataDidChangeChangeNotification = @"com.mobileTuts.MTRainWeatherDataDidChangeChangeNotification";
2
NSString * const MTRainTemperatureUnitDidChangeNotification = @"com.mobileTuts.MTRainTemperatureUnitDidChangeNotification";

Langkah 2: Cuaca View Controller

Setelah menerima respons dari API ramalan, kita perlu menyimpannya sehingga kita dapat menggunakannya nanti untuk memperbarui tampilan. Buat dua sifat pribadi di MTWeatherViewController.m, (1) respon (jenis NSDictionary) yang akan memegang respon dari API ramalan dan (2) ramalan (jenis NSArray) yang akan memegang subset dari respon, data cuaca untuk jam berikutnya.

1
#import "MTWeatherViewController.h"

2
3
#import "MTForecastClient.h"

4
5
@interface MTWeatherViewController () <CLLocationManagerDelegate> {
6
    BOOL _locationFound;
7
}
8
9
@property (strong, nonatomic) NSDictionary *location;
10
@property (strong, nonatomic) NSDictionary *response;
11
@property (strong, nonatomic) NSArray *forecast;
12
13
@property (strong, nonatomic) CLLocationManager *locationManager;
14
15
@end

Untuk menerima pemberitahuan, kita perlu untuk memperbarui initWithNibName:bundle: seperti yang ditunjukkan di bawah ini (MTWeatherViewController.m). Dalam weatherDataDidChangeChange:, kita menyimpan respon dari API ramalan dalam respon dan ramalan dan kami memperbarui tampilan Lihat controller. Dalam temperatureUnitDidChange, kita hanya perlu untuk memperbarui tampilan untuk mencerminkan suasana berubah.

1
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
2
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
3
4
    if (self) {
5
        // Initialize Location Manager

6
        self.locationManager = [[CLLocationManager alloc] init];
7
8
        // Configure Location Manager

9
        [self.locationManager setDelegate:self];
10
        [self.locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer];
11
12
        // Add Observer

13
        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
14
        [nc addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
15
        [nc addObserver:self selector:@selector(reachabilityStatusDidChange:) name:MTRainReachabilityStatusDidChangeNotification object:nil];
16
        [nc addObserver:self selector:@selector(weatherDataDidChangeChange:) name:MTRainWeatherDataDidChangeChangeNotification object:nil];
17
        [nc addObserver:self selector:@selector(temperatureUnitDidChange:) name:MTRainTemperatureUnitDidChangeNotification object:nil];
18
    }
19
20
    return self;
21
}
1
- (void)weatherDataDidChangeChange:(NSNotification *)notification {
2
    // Update Response & Forecast

3
    [self setResponse:[notification userInfo]];
4
    [self setForecast:self.response[@"hourly"][@"data"]];
5
6
    // Update View

7
    [self updateView];
8
}
1
- (void)temperatureUnitDidChange:(NSNotification *)notification {
2
    // Update View

3
    [self updateView];
4
}

Langkah 3: Ramalan View Controller

Langkah-langkah hampir identik di kelas MTForecastViewController. Kami memperbarui initWithNibName:bundle: seperti yang ditunjukkan di bawah ini, membuat dua sifat (respon dan ramalan), dan menerapkan weatherDataDidChangeChange: dan temperatureUnitDidChange:. Perbedaannya adalah data cuaca yang disimpan dalam ramalan. Kami akan menerapkan updateView agak kemudian dalam tutorial ini, tetapi itu adalah praktik yang baik untuk membuat sebuah implementasi rintisan untuk menyingkirkan peringatan kompiler apapun.

1
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
2
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
3
4
    if (self) {
5
        // Add Observer

6
        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
7
        [nc addObserver:self selector:@selector(weatherDataDidChangeChange:) name:MTRainWeatherDataDidChangeChangeNotification object:nil];
8
        [nc addObserver:self selector:@selector(temperatureUnitDidChange:) name:MTRainTemperatureUnitDidChangeNotification object:nil];
9
    }
10
11
    return self;
12
}
1
#import "MTForecastViewController.h"

2
3
@interface MTForecastViewController ()
4
5
@property (strong, nonatomic) NSDictionary *response;
6
@property (strong, nonatomic) NSArray *forecast;
7
8
@end
1
- (void)weatherDataDidChangeChange:(NSNotification *)notification {
2
    // Update Response & Forecast

3
    [self setResponse:[notification userInfo]];
4
    [self setForecast:self.response[@"daily"][@"data"]];
5
6
    // Update View

7
    [self updateView];
8
}
1
- (void)temperatureUnitDidChange:(NSNotification *)notification {
2
    // Update View

3
    [self updateView];
4
}
1
- (void)updateView {
2
3
}

2. tampilan pengguna antarmuka Pusat

Langkah 1: Outlet dan tindakan

Meskipun tampilan pusat berisi banyak informasi, hal ini tidak begitu sulit untuk menerapkan. Mari kita mulai dengan membuat beberapa outlet dan satu tindakan baru. Memperbarui MTWeatherViewController.h seperti yang ditunjukkan di bawah ini. Kembali Chris di desain untuk lebih memahami lokasi dan tujuan dari setiap elemen antarmuka pengguna. Perbedaan dengan Chris's desain adalah bahwa kita akan mengganti ikon kalender di kanan atas dengan tombol refresh bahwa kita diciptakan dalam tutorial sebelumnya. Data cuaca untuk jam berikutnya akan disajikan dalam tampilan koleksi, yang menyiratkan bahwa kelas MTWeatherViewController kebutuhan untuk menyesuaikan diri dengan UICollectionViewDataSource, UICollectionViewDelegate, dan UICollectionViewDelegateFlowLayout protokol.

1
#import <UIKit/UIKit.h>

2
3
#import "MTLocationsViewController.h"

4
5
@interface MTWeatherViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, MTLocationsViewControllerDelegate>
6
7
@property (weak, nonatomic) IBOutlet UIButton *buttonLocation;
8
@property (weak, nonatomic) IBOutlet UIButton *buttonRefresh;
9
10
@property (weak, nonatomic) IBOutlet UILabel *labelDate;
11
@property (weak, nonatomic) IBOutlet UILabel *labelTemp;
12
@property (weak, nonatomic) IBOutlet UILabel *labelTime;
13
@property (weak, nonatomic) IBOutlet UILabel *labelWind;
14
@property (weak, nonatomic) IBOutlet UILabel *labelRain;
15
@property (weak, nonatomic) IBOutlet UILabel *labelLocation;
16
17
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
18
19
@end

Kita juga perlu menambahkan tindakan untuk lokasi tombol di kiri atas. Buka MTWeatherViewController.m dan menambahkan tindakan baru bernama openLeftView:. Dalam openLeftView:, kami memberitahu controller pemandangan pemandangan dek controller untuk beralih tampilan kiri. Ingat bahwa itu juga mungkin untuk menggesek dari kiri ke kanan untuk membuka tampilan kiri.

1
- (IBAction)openLeftView:(id)sender {
2
    [self.viewDeckController toggleLeftViewAnimated:YES];
3
}

Langkah 2: Membuat antarmuka pengguna

Buka MTWeatherViewController.xib dan menciptakan antarmuka pengguna seperti yang ditunjukkan pada gambar 2. Sementara membuat antarmuka pengguna, penting sekali untuk menguji bahwa antarmuka pengguna menampilkan dengan benar pada layar 3.5" dan iPhone 5 4" layar. Anda dapat menguji ini dengan memilih tampilan view controller dan mengubah atribut ukuran di Inspektur atribut. Untuk mencapai hasil yang diinginkan, Anda perlu men-tweak kendala elemen antarmuka pengguna autolayout. Tujuannya adalah untuk membuat data cuaca tetap ke atas tampilan, sementara tampilan koleksi terpaku ke bawah. Ikon di samping waktu, angin dan hujan label adalah contoh dari UIImageView.

Create a Weather App with Forecast – User Interface - Creating the User Interface of the Weather View Controller Create a Weather App with Forecast – User Interface - Creating the User Interface of the Weather View Controller Create a Weather App with Forecast – User Interface - Creating the User Interface of the Weather View Controller
Gambar 2: Menciptakan antarmuka pengguna cuaca View Controller

Mengkonfigurasi label dan tombol seperti yang ditunjukkan pada gambar 2. Ini termasuk benar menyelaraskan teks label, menetapkan jenis kedua tombol kebiasaan, membuat pemilik File tampilan koleksi dataSource dan delegasi, dan menetapkan arah gulir koleksi pemandangan aliran layout ke horisontal. Saya seorang penggemar Gill Sans sehingga font yang saya memilih untuk menggunakan untuk proyek ini. Sebelum beralih kembali ke file implementasi cuaca Lihat controller, menghubungkan outlet dan tindakan yang kita buat sebelumnya. Di samping label dan tombol, saya juga telah menambahkan tampilan gambar untuk tampilan controller lihat untuk menampilkan gambar latar belakang.

Seperti yang saya sebutkan dalam pendahuluan, Anda dapat menemukan karya seni aplikasi di source file tutorial ini. Buat folder dengan nama Artwork dalam proyek Xcode Anda dan tarik karya seni dalam folder ini.

Langkah 3: Mempopulasikan antarmuka pengguna

Kami saat ini log respon dari API ramalan Xcode di konsol. Untuk mulai menggunakan data cuaca, kita perlu untuk memperbarui fetchWeatherData metode seperti ditunjukkan di bawah ini. Di blok penyelesaian requestWeatherForCoordinate:completion:, kita bersembunyi kemajuan HUD dan mengirimkan pemberitahuan pada benang. Kami memanfaatkan fungsi dispatch_async dan melewati antrian benang sebagai argumen pertama. Pemberitahuan userInfo Kamus adalah respon dari permintaan.

1
- (void)fetchWeatherData {
2
    if ([[MTForecastClient sharedClient] networkReachabilityStatus] == AFNetworkReachabilityStatusNotReachable) return;
3
4
    // Show Progress HUD

5
    [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];
6
7
    // Query Forecast API

8
    double lat = [[_location objectForKey:MTLocationKeyLatitude] doubleValue];
9
    double lng = [[_location objectForKey:MTLocationKeyLongitude] doubleValue];
10
    [[MTForecastClient sharedClient] requestWeatherForCoordinate:CLLocationCoordinate2DMake(lat, lng) completion:^(BOOL success, NSDictionary *response) {
11
        // Dismiss Progress HUD

12
        [SVProgressHUD dismiss];
13
14
        if (response && [response isKindOfClass:[NSDictionary class]]) {
15
            dispatch_async(dispatch_get_main_queue(), ^{
16
                // Post Notification on Main Thread

17
                NSNotification *notification = [NSNotification notificationWithName:MTRainWeatherDataDidChangeChangeNotification object:nil userInfo:response];
18
                [[NSNotificationCenter defaultCenter] postNotification:notification];
19
            });
20
        }
21
    }];
22
}

Cuaca dan prakiraan view controller yang kedua pengamat pemberitahuan MTRainWeatherDataDidChangeChangeNotification. Cuaca Lihat controller memanggil weatherDataDidChangeChange:, yang pada gilirannya memanggil updateView. Dalam updateView, kita memanggil updateCurrentWeather dan memperbarui tampilan koleksi dengan mengirim pesan reloadData.

1
- (void)updateView {
2
    // Update Location Label

3
    [self.labelLocation setText:[self.location objectForKey:MTLocationKeyCity]];
4
5
    // Update Current Weather

6
    [self updateCurrentWeather];
7
8
    // Reload Collection View

9
    [self.collectionView reloadData];
10
}

Sebelum kita menerapkan updateCurrentWeather, saya ingin mengambil jalan memutar kecil. Kami akan menampilkan nilai-nilai suhu di berbagai tempat aplikasi, dan karena kami mendukung Fahrenheit dan Celcius ini dapat menjadi rumit. Hal ini karena itu berguna untuk membuat sebuah kelas yang centralizes logika ini sehingga kita tidak perlu kekacauan kode kita dasar dengan jika pernyataan dan suhu konversi.

Langkah 4: Menciptakan kelas pengaturan

Sebelum kita membuat kelas yang menangani konversi suhu, kita harus mampu menyimpan pengaturan suhu saat ini dalam database pengguna default. Kembali MTConstants.h/.m dan menyatakan konstan string dengan nama MTRainUserDefaultsTemperatureUnit.

1
extern NSString * const MTRainUserDefaultsTemperatureUnit;
1
NSString * const MTRainUserDefaultsTemperatureUnit = @"temperatureUnit";

Untuk memudahkan bekerja dengan pengaturan, saya sering membuat kategori pada NSUserDefaults yang memungkinkan saya untuk cepat dan elegan mengakses aplikasi pengaturan. Biarkan saya menunjukkan kepada Anda apa yang saya maksud. Buat kategori Objective-C baru (gambar 3), nama kategori pembantu, dan membuat kategori pada NSUserDefaults (gambar 4). Dalam NSUserDefaults+Helpers.h, kita mendeklarasikan tiga kelas metode seperti ditunjukkan di bawah.

Create a Weather App with Forecast – User Interface - Creating a New Objective-C Category Create a Weather App with Forecast – User Interface - Creating a New Objective-C Category Create a Weather App with Forecast – User Interface - Creating a New Objective-C Category
Gambar 3: Membuat Objective-C kategori baru
Create a Weather App with Forecast – User Interface - Creating a Category on NSUserDefaults Create a Weather App with Forecast – User Interface - Creating a Category on NSUserDefaults Create a Weather App with Forecast – User Interface - Creating a Category on NSUserDefaults
Gambar 4: Membuat kategori di NSUserDefaults
1
#import <Foundation/Foundation.h>

2
3
@interface NSUserDefaults (Helpers)
4
5
#pragma mark -

6
#pragma mark Temperature

7
+ (BOOL)isDefaultCelcius;
8
+ (void)setDefaultToCelcius;
9
+ (void)setDefaultToFahrenheit;
10
11
@end

Meskipun metode ini tidak magis, mereka sangat berguna. Metode pertama, isDefaultCelcius, mengatakan jika unit suhu diatur ke Celcius atau tidak. Dua metode lain membuatnya sangat mudah untuk beralih antara Celsius dan Fahrenheit. Tidak hanya melakukan kami memperbarui pengguna default database, kami juga posting pemberitahuan yang menginformasikan pengamat perubahan.

1
+ (BOOL)isDefaultCelcius {
2
    return [[NSUserDefaults standardUserDefaults] integerForKey:MTRainUserDefaultsTemperatureUnit] == 1;
3
}
4
5
+ (void)setDefaultToCelcius {
6
    // Update User Defaults

7
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
8
    [ud setInteger:1 forKey:MTRainUserDefaultsTemperatureUnit];
9
    [ud synchronize];
10
11
    // Post Notification

12
    [[NSNotificationCenter defaultCenter] postNotificationName:MTRainTemperatureUnitDidChangeNotification object:nil];
13
}
14
15
+ (void)setDefaultToFahrenheit {
16
    // Update User Defaults

17
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
18
    [ud setInteger:0 forKey:MTRainUserDefaultsTemperatureUnit];
19
    [ud synchronize];
20
21
    // Post Notification

22
    [[NSNotificationCenter defaultCenter] postNotificationName:MTRainTemperatureUnitDidChangeNotification object:nil];
23
}

Sekarang saatnya untuk membuat kelas pengaturan yang saya tulis sebelumnya. Solusinya sangat mudah. Membuat sebuah class baru Objective-C, nama itu MTSettings dan membuat sebuah subclass dari NSObject (gambar 5). Di MTSettings.h, kami menyatakan metode kelas satu, formatTemperature:. Dalam MTSettings.m, kita impor header kategori kami menciptakan beberapa saat yang lalu dan menerapkan formatTemperature: seperti yang ditunjukkan di bawah ini. Metode menerima contoh NSNumber, mengkonversi ke pelampung, dan mengembalikan sebuah string yang diformat berdasarkan pengaturan suhu.

Create a Weather App with Forecast – User Interface - Creating the MTSettings Class Create a Weather App with Forecast – User Interface - Creating the MTSettings Class Create a Weather App with Forecast – User Interface - Creating the MTSettings Class
Gambar 5: Menciptakan kelas MTSettings
1
#import <Foundation/Foundation.h>

2
3
@interface MTSettings : NSObject
4
5
#pragma mark -

6
#pragma mark Convenience Methods

7
+ (NSString *)formatTemperature:(NSNumber *)temperature;
8
9
@end
1
#import "NSUserDefaults+Helpers.h"
1
+ (NSString *)formatTemperature:(NSNumber *)temperature {
2
    float value = [temperature floatValue];
3
4
    if ([NSUserDefaults isDefaultCelcius]) {
5
        value = (value  -  32.0)  *  (5.0 / 9.0);
6
    }
7
8
    return [NSString stringWithFormat:@"%.0f°", value];
9
}

Sebelum kita melanjutkan, menambahkan pernyataan impor untuk kelas MTSettings file header Installation proyek sehingga kita dapat menggunakannya sepanjang proyek.

1
#import <Availability.h>

2
3
#ifndef __IPHONE_3_0

4
#warning "This project uses features only available in iOS SDK 3.0 and later."

5
#endif

6
7
#ifdef __OBJC__

8
    #import <UIKit/UIKit.h>

9
    #import <Foundation/Foundation.h>

10
    #import <QuartzCore/QuartzCore.h>

11
    #import <CoreLocation/CoreLocation.h>

12
    #import <MobileCoreServices/MobileCoreServices.h>

13
    #import <SystemConfiguration/SystemConfiguration.h>

14
15
    #import "AFNetworking.h"

16
    #import "SVProgressHUD.h"

17
    #import "IIViewDeckController.h"

18
19
    #import "MTSettings.h"

20
    #import "MTConstants.h"

21
#endif

Sekarang saatnya untuk menerapkan updateCurrentWeather di kelas MTWeatherViewController. Data untuk cuaca saat ini adalah subset dari respon dari API ramalan. Pelaksanaan updateCurrentWeather cukup sederhana. Satu-satunya peringatan yang harus diperhatikan adalah probabilitas curah hujan. Jika nilai ini sama dengan 0, precipProbability kunci tidak termasuk dalam respon. Itulah alasan bahwa kita pertama-tama memeriksa keberadaan precipProbability kunci dalam kamus respon.

1
- (void)updateCurrentWeather {
2
    // Weather Data

3
    NSDictionary *data = [self.response objectForKey:@"currently"];
4
5
    // Update Date Label

6
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
7
    [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
8
    [dateFormatter setDateFormat:@"EEEE, MMM d"];
9
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:[data[@"time"] doubleValue]];
10
    [self.labelDate setText:[dateFormatter stringFromDate:date]];
11
12
    // Update Temperature Label

13
    [self.labelTemp setText:[MTSettings formatTemperature:data[@"temperature"]]];
14
15
    // Update Time Label

16
    NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
17
    [timeFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
18
    [timeFormatter setDateFormat:@"ha"];
19
    [self.labelTime setText:[timeFormatter stringFromDate:[NSDate date]]];
20
21
    // Update Wind Label

22
    [self.labelWind setText:[NSString stringWithFormat:@"%.0fMP", [data[@"windSpeed"] floatValue]]];
23
24
    // Update Rain Label

25
    float rainProbability = 0.0;
26
    if (data[@"precipProbability"]) {
27
        rainProbability = [data[@"precipProbability"] floatValue] * 100.0;
28
    }
29
30
    [self.labelRain setText:[NSString stringWithFormat:@"%.0f%%", rainProbability]];
31
}

Langkah 5: Mempopulasikan tampilan koleksi

Untuk mengisi koleksi pandangan, pertama kita perlu menciptakan UICollectionViewCell subclass. Membuat sebuah class baru Objective-C, nama itu MTHourCell dan membuat sebuah subclass dari UICollectionViewCell (gambar 6). Membuat meja kustom atau koleksi Lihat sel dapat melelahkan dan melelahkan. Jika Anda ingin mempelajari lebih lanjut tentang membuat meja kustom dan sel-sel lihat koleksi, maka saya sarankan Anda Lihatlah tutorial saya menulis beberapa minggu lalu.

Create a Weather App with Forecast – User Interface - Creating a Custom Collection View Create a Weather App with Forecast – User Interface - Creating a Custom Collection View Create a Weather App with Forecast – User Interface - Creating a Custom Collection View
Gambar 6: Membuat tampilan kustom koleksi

Dalam antarmuka MTHourCell, kami menyatakan sifat empat jenis UILabel. Kami tidak melakukan banyak keajaiban di MTHourcell.m seperti yang Anda lihat di bawah ini. Untuk lebih memahami initWithFrame: metode, kembali desain saya menunjukkan kepada Anda di awal artikel ini. Saya tidak akan membahas pelaksanaan initWithFrame: secara detail, tetapi saya ingin menunjukkan bahwa saya menggunakan preprocessor menentukan warna teks label. Saya menambahkan preprocess untuk MTConstants.h untuk membuatnya tersedia untuk seluruh proyek (lihat bawah).

1
#import <UIKit/UIKit.h>

2
3
@interface MTHourCell : UICollectionViewCell
4
5
@property (strong, nonatomic) UILabel *labelTime;
6
@property (strong, nonatomic) UILabel *labelTemp;
7
@property (strong, nonatomic) UILabel *labelWind;
8
@property (strong, nonatomic) UILabel *labelRain;
9
10
@end
1
#import "MTHourCell.h"

2
3
#define kMTLabelBottomWidth 40.0

4
#define kMTLabelBottomHeight 40.0

5
6
@interface MTHourCell ()
7
8
@end
9
10
@implementation MTHourCell
11
12
- (id)initWithFrame:(CGRect)frame {
13
    self = [super initWithFrame:frame];
14
15
    if (self) {
16
        // Helpers

17
        CGSize size = self.contentView.frame.size;
18
19
        // Initialize Label Time

20
        self.labelTime = [[UILabel alloc] initWithFrame:CGRectMake(30.0, 0.0, 50.0, 40.0)];
21
22
        // Configure Label Time

23
        [self.labelTime setBackgroundColor:[UIColor clearColor]];
24
        [self.labelTime setTextColor:[UIColor whiteColor]];
25
        [self.labelTime setFont:[UIFont fontWithName:@"GillSans-Light" size:18.0]];
26
        [self.labelTime setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin)];
27
        [self.contentView addSubview:self.labelTime];
28
29
        // Initialize Label Temp

30
        self.labelTemp = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 46.0, 80.0, 44.0)];
31
32
        // Configure Label Temp

33
        [self.labelTemp setBackgroundColor:[UIColor clearColor]];
34
        [self.labelTemp setTextAlignment:NSTextAlignmentCenter];
35
        [self.labelTemp setTextColor:kMTColorGray];
36
        [self.labelTemp setFont:[UIFont fontWithName:@"GillSans-Bold" size:40.0]];
37
        [self.labelTemp setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin)];
38
        [self.contentView addSubview:self.labelTemp];
39
40
        // Initialize Label Wind

41
        self.labelWind = [[UILabel alloc] initWithFrame:CGRectMake(0.0, size.height - kMTLabelBottomHeight, kMTLabelBottomWidth, kMTLabelBottomHeight)];
42
43
        // Configure Label Wind

44
        [self.labelWind setBackgroundColor:[UIColor clearColor]];
45
        [self.labelWind setTextAlignment:NSTextAlignmentCenter];
46
        [self.labelWind setTextColor:kMTColorGray];
47
        [self.labelWind setFont:[UIFont fontWithName:@"GillSans-Light" size:16.0]];
48
        [self.labelWind setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin)];
49
        [self.contentView addSubview:self.labelWind];
50
51
        // Initialize Label Rain

52
        self.labelRain = [[UILabel alloc] initWithFrame:CGRectMake(size.width - kMTLabelBottomWidth, size.height - kMTLabelBottomHeight, kMTLabelBottomWidth, kMTLabelBottomHeight)];
53
54
        // Configure Label Rain

55
        [self.labelRain setBackgroundColor:[UIColor clearColor]];
56
        [self.labelRain setTextAlignment:NSTextAlignmentCenter];
57
        [self.labelRain setTextColor:kMTColorGray];
58
        [self.labelRain setFont:[UIFont fontWithName:@"GillSans-Light" size:16.0]];
59
        [self.labelRain setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin)];
60
        [self.contentView addSubview:self.labelRain];
61
62
        // Background View

63
        UIImage *backgroundImage = [[UIImage imageNamed:@"background-hour-cell"] resizableImageWithCapInsets:UIEdgeInsetsMake(40.0, 10.0, 10.0, 10.0)];
64
        UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, size.width, size.height)];
65
        [backgroundView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
66
        [backgroundView setImage:backgroundImage];
67
        [self setBackgroundView:backgroundView];
68
    }
69
70
    return self;
71
}
72
73
@end
1
#define kMTColorGray [UIColor colorWithRed:0.737 green:0.737 blue:0.737 alpha:1.0]

2
#define kMTColorGreen [UIColor colorWithRed:0.325 green:0.573 blue:0.388 alpha:1.0]

3
#define kMTColorOrange [UIColor colorWithRed:1.000 green:0.306 blue:0.373 alpha:1.0]

Seperti yang Anda lihat di bawah, mengimplementasikan protokol UICollectionViewDataSource, UICollectionViewDelegate dan UICollectionViewDelegateFlowLayout sangat mirip dengan mengimplementasikan protokol UITableViewDataSource dan UITableViewDelegate.

1
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
2
    return self.forecast ? 1 : 0;
3
}
4
5
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
6
    return [self.forecast count];
7
}
8
9
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
10
    MTHourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:HourCell forIndexPath:indexPath];
11
12
    // Fetch Data

13
    NSDictionary *data = [self.forecast objectAtIndex:indexPath.row];
14
15
    // Initialize Date Formatter

16
    NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
17
    [timeFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
18
    [timeFormatter setDateFormat:@"ha"];
19
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:[data[@"time"] doubleValue]];
20
21
    // Configure Cell

22
    [cell.labelTime setText:[timeFormatter stringFromDate:date]];
23
    [cell.labelTemp setText:[MTSettings formatTemperature:data[@"temperature"]]];
24
    [cell.labelWind setText:[NSString stringWithFormat:@"%.0fMP", [data[@"windSpeed"] floatValue]]];
25
26
    float rainProbability = 0.0;
27
    if (data[@"precipProbability"]) {
28
        rainProbability = [data[@"precipProbability"] floatValue] * 100.0;
29
    }
30
31
    [cell.labelRain setText:[NSString stringWithFormat:@"%.0f%%", rainProbability]];
32
33
    return cell;
34
}
1
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
2
    return CGSizeMake(80.0, 120.0);
3
}
4
5
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
6
    return UIEdgeInsetsMake(0.0, 10.0, 0.0, 10.0);
7
}

Untuk melakukan semua pekerjaan ini, kita perlu (1) impor file header dari MTHourCell, (2) menyatakan konstan string statis yang berfungsi sebagai pengenal kembali sel, dan (3) memberitahu tampilan koleksi untuk menggunakan MTHourCell kelas untuk instantiate sel-sel baru. Di viewDidLoad, kami juga menetapkan warna latar belakang pemandangan koleksi untuk transparant.

1
#import "MTHourCell.h"
1
static NSString *HourCell = @"HourCell";
1
- (void)viewDidLoad {
2
    [super viewDidLoad];
3
4
    // Load Location

5
    self.location = [[NSUserDefaults standardUserDefaults] objectForKey:MTRainUserDefaultsLocation];
6
7
    if (!self.location) {
8
        [self.locationManager startUpdatingLocation];
9
    }
10
11
    // Configure Collection View

12
    [self.collectionView setBackgroundColor:[UIColor clearColor]];
13
    [self.collectionView registerClass:[MTHourCell class] forCellWithReuseIdentifier:HourCell];
14
}

3. pengguna antarmuka pandangan yang benar

Langkah 1: outlet

Meskipun pandangan yang benar menampilkan banyak data, pelaksanaan MTForecastViewController kelas tidak yang kompleks. Kita mulai dengan membuat jalan keluar untuk tampilan tabel di MTForecastViewController.h dan sesuai kelas protokol UITableViewDataSource dan UITableViewDelegate.

1
#import <UIKit/UIKit.h>

2
3
@interface MTForecastViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
4
5
@property (weak, nonatomic) IBOutlet UITableView *tableView;
6
7
@end

Langkah 2: Membuat antarmuka pengguna

Membuat antarmuka pengguna sederhana seperti menambahkan tampilan tabel ke tampilan controller pemandangan, menghubungkan outlet kami menciptakan beberapa saat yang lalu, dan menetapkan pemilik File sebagai tampilan tabel dataSource dan delegasi (gambar 7).

Create a Weather App with Forecast – User Interface - Creating the User Interface of the Forecast View Controller Create a Weather App with Forecast – User Interface - Creating the User Interface of the Forecast View Controller Create a Weather App with Forecast – User Interface - Creating the User Interface of the Forecast View Controller
Gambar 7: Menciptakan antarmuka pengguna ramalan View Controller

Langkah 3: Mempopulasikan tampilan tabel

Sebelum kita mengisi tampilan tabel dengan data, kita perlu menciptakan UITableViewCell subclass. Membuat sebuah class baru Objective-C, nama itu MTDayCell dan membuat sebuah subclass dari UITableViewCell (gambar 8). Buka MTDayCell.h dan menyatakan lima outlet tipe UILabel. Sebagai dengan kelas MTHourCell, pelaksanaan MTDayCell tidak terlalu sulit seperti yang Anda lihat di bawah ini.

Create a Weather App with Forecast – User Interface - Creating a Custom Table View Cell Create a Weather App with Forecast – User Interface - Creating a Custom Table View Cell Create a Weather App with Forecast – User Interface - Creating a Custom Table View Cell
Gambar 8: Menciptakan sebuah meja kustom Lihat sel
1
#import <UIKit/UIKit.h>

2
3
@interface MTDayCell : UITableViewCell
4
5
@property (strong, nonatomic) UILabel *labelDay;
6
@property (strong, nonatomic) UILabel *labelDate;
7
@property (strong, nonatomic) UILabel *labelTemp;
8
@property (strong, nonatomic) UILabel *labelWind;
9
@property (strong, nonatomic) UILabel *labelRain;
10
11
@end
1
#import "MTDayCell.h"

2
3
#define kMTCalendarWidth 44.0

4
#define kMTCalendarHeight 80.0

5
#define kMTCalendarMarginLeft 60.0

6
#define kMTLabelRightWidth 30.0

7
#define kMTLabelRightHeight 14.0

8
9
@interface MTDayCell ()
10
11
@property (strong, nonatomic) UIImageView *imageViewCalendar;
12
13
@end
14
15
@implementation MTDayCell
16
17
#pragma mark -

18
#pragma mark Initialization

19
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
20
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
21
22
    if (self) {
23
        // Helpers

24
        CGSize size = self.contentView.frame.size;
25
26
        // Configure Table View Cell

27
        [self setSelectionStyle:UITableViewCellSelectionStyleNone];
28
29
        // Initialize Image View Clock

30
        self.imageViewCalendar = [[UIImageView alloc] initWithFrame:CGRectMake(kMTCalendarMarginLeft, 0.0, kMTCalendarWidth, kMTCalendarHeight)];
31
32
        // Configure Image View Clock

33
        [self.imageViewCalendar setContentMode:UIViewContentModeCenter];
34
        [self.imageViewCalendar setImage:[UIImage imageNamed:@"background-calendar-day-cell"]];
35
        [self.imageViewCalendar setAutoresizingMask:(UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin)];
36
        [self.contentView addSubview:self.imageViewCalendar];
37
38
        // Initialize Label Day

39
        self.labelDay = [[UILabel alloc] initWithFrame:CGRectMake(kMTCalendarMarginLeft, 10.0, kMTCalendarWidth, 20.0)];
40
41
        // Configure Label Day

42
        [self.labelDay setTextColor:[UIColor whiteColor]];
43
        [self.labelDay setTextAlignment:NSTextAlignmentCenter];
44
        [self.labelDay setBackgroundColor:[UIColor clearColor]];
45
        [self.labelDay setFont:[UIFont fontWithName:@"GillSans" size:14.0]];
46
        [self.labelDay setAutoresizingMask:(UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin)];
47
        [self.contentView addSubview:self.labelDay];
48
49
        // Initialize Label Date

50
        self.labelDate = [[UILabel alloc] initWithFrame:CGRectMake(kMTCalendarMarginLeft, 20.0, kMTCalendarWidth, 60.0)];
51
52
        // Configure Label Date

53
        [self.labelDate setTextColor:kMTColorGray];
54
        [self.labelDate setTextAlignment:NSTextAlignmentCenter];
55
        [self.labelDate setBackgroundColor:[UIColor clearColor]];
56
        [self.labelDate setFont:[UIFont fontWithName:@"GillSans" size:24.0]];
57
        [self.labelDate setAutoresizingMask:(UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin)];
58
        [self.contentView addSubview:self.labelDate];
59
60
        // Initialize Label Wind

61
        self.labelWind = [[UILabel alloc] initWithFrame:CGRectMake(size.width - kMTLabelRightWidth, (size.height / 2.0) - kMTLabelRightHeight, kMTLabelRightWidth, kMTLabelRightHeight)];
62
63
        // Configure Label Wind

64
        [self.labelWind setTextColor:kMTColorGray];
65
        [self.labelWind setTextAlignment:NSTextAlignmentCenter];
66
        [self.labelWind setBackgroundColor:[UIColor clearColor]];
67
        [self.labelWind setFont:[UIFont fontWithName:@"GillSans" size:12.0]];
68
        [self.labelWind setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin)];
69
        [self.contentView addSubview:self.labelWind];
70
71
        // Initialize Label Rain

72
        self.labelRain = [[UILabel alloc] initWithFrame:CGRectMake(size.width - kMTLabelRightWidth, (size.height / 2.0), kMTLabelRightWidth, kMTLabelRightHeight)];
73
74
        // Configure Label Rain

75
        [self.labelRain setTextColor:kMTColorGray];
76
        [self.labelRain setTextAlignment:NSTextAlignmentCenter];
77
        [self.labelRain setBackgroundColor:[UIColor clearColor]];
78
        [self.labelRain setFont:[UIFont fontWithName:@"GillSans" size:12.0]];
79
        [self.labelRain setAutoresizingMask:(UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin)];
80
        [self.contentView addSubview:self.labelRain];
81
82
        // Initialize Label Temp

83
        self.labelTemp = [[UILabel alloc] initWithFrame:CGRectMake(kMTCalendarWidth + kMTCalendarMarginLeft + 12.0, 0.0, size.width - kMTCalendarWidth - kMTCalendarMarginLeft - kMTLabelRightWidth - 12.0, size.height)];
84
85
        // Configure Label Temp

86
        [self.labelTemp setTextColor:kMTColorGray];
87
        [self.labelTemp setTextAlignment:NSTextAlignmentCenter];
88
        [self.labelTemp setBackgroundColor:[UIColor clearColor]];
89
        [self.labelTemp setFont:[UIFont fontWithName:@"GillSans-Bold" size:40.0]];
90
        [self.labelTemp setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
91
        [self.contentView addSubview:self.labelTemp];
92
    }
93
94
    return self;
95
}
96
97
@end

Implementasi protokol sumber data tampilan tabel sangat mirip dengan koleksi tampilan data sumber protokol yang kita lihat sebelumnya. Kami juga menerapkan salah satu metode meja Lihat delegasi protokol, tableView:heightForRowAtIndexPath:, untuk mengatur ketinggian baris untuk 80.0.

1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
2
    return self.forecast ? 1 : 0;
3
}
4
5
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
6
    return [self.forecast count];
7
}
8
9
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
10
    MTDayCell *cell = [tableView dequeueReusableCellWithIdentifier:DayCell forIndexPath:indexPath];
11
12
    // Fetch Data

13
    NSDictionary *data = [self.forecast objectAtIndex:indexPath.row];
14
15
    // Initialize Date Formatter

16
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
17
    [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
18
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:[data[@"time"] doubleValue]];
19
20
    // Configure Cell

21
    [dateFormatter setDateFormat:@"EEE"];
22
    [cell.labelDay setText:[dateFormatter stringFromDate:date]];
23
24
    [dateFormatter setDateFormat:@"d"];
25
    [cell.labelDate setText:[dateFormatter stringFromDate:date]];
26
27
    float tempMin = [data[@"temperatureMin"] floatValue];
28
    float tempMax = [data[@"temperatureMax"] floatValue];
29
    [cell.labelTemp setText:[NSString stringWithFormat:@"%.0f°/%.0f°", tempMin, tempMax]];
30
31
    [cell.labelWind setText:[NSString stringWithFormat:@"%.0f", [data[@"windSpeed"] floatValue]]];
32
33
    float rainProbability = 0.0;
34
    if (data[@"precipProbability"]) {
35
        rainProbability = [data[@"precipProbability"] floatValue] * 100.0;
36
    }
37
38
    [cell.labelRain setText:[NSString stringWithFormat:@"%.0f", rainProbability]];
39
40
    return cell;
41
}
1
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
2
    return 80.0;
3
}

Untuk melakukan semua pekerjaan ini, kita perlu (1) mengimpor file header kelas MTDayCell, (2) menyatakan konstan string statis untuk pengenal kembali sel, dan (3) mendaftar MTDayCell sebagai kelas untuk sel menggunakan kembali pengenal di viewDidLoad. Di updateView, kami reload tampilan tabel.

1
#import "MTDayCell.h"
1
static NSString *DayCell = @"DayCell";
1
- (void)viewDidLoad {
2
    [super viewDidLoad];
3
4
    // Configure Table View

5
    [self.tableView registerClass:[MTDayCell class] forCellReuseIdentifier:DayCell];
6
}
1
- (void)updateView {
2
    // Reload Table View

3
    [self.tableView reloadData];
4
}

4. pengguna antarmuka pandangan yang benar

Langkah 1: Memperbarui antarmuka pengguna

Hal ini jelas bahwa kita perlu membuat beberapa perubahan signifikan ke lokasi pemandangan controller untuk menerapkan desain Chris. Tampilan tabel lokasi pemandangan controller akan mencakup dua bagian bukan satu. Bagian atas akan menampilkan lokasi disimpan sementara bagian bawah disediakan untuk pengaturan suhu. Mulai dengan membuka MTLocationsViewController.xib dan menghapus bar navigasi yang kami tambahkan di artikel sebelumnya (gambar 9). Ini berarti bahwa kita juga bisa menghapus outlet untuk tombol edit di MTLocationsViewController.h dan editLocations tindakan di MTLocationsViewController.m.

Create a Weather App with Forecast – User Interface - Updating the User Interface of the Locations View Controller Create a Weather App with Forecast – User Interface - Updating the User Interface of the Locations View Controller Create a Weather App with Forecast – User Interface - Updating the User Interface of the Locations View Controller
Gambar 9: Memperbarui antarmuka pengguna lokasi View Controller

Langkah 2: Membuat sel lokasi

Sel-sel yang menampilkan lokasi memiliki sebuah tombol delete di sebelah kiri. Untuk membuat karya ini, kita perlu membuat sel Lihat tabel kustom. Membuat lain subclass UITableViewCell dan nama MTLocationCell (gambar 10). Buka MTLocationCell.h dan membuat dua sifat, (1) buttonDelete (UIButton) dan (2) labelLocation (UILabel). Seperti yang Anda lihat, pelaksanaan MTLocationCell kurang kompleks daripada orang-orang MTHourCell dan MTDayCell.

Create a Weather App with Forecast – User Interface - Creating a Custom Table View Cell Create a Weather App with Forecast – User Interface - Creating a Custom Table View Cell Create a Weather App with Forecast – User Interface - Creating a Custom Table View Cell
Gambar 10: Membuat sel Lihat tabel kustom
1
#import <UIKit/UIKit.h>

2
3
@interface MTLocationCell : UITableViewCell
4
5
@property (strong, nonatomic) UIButton *buttonDelete;
6
@property (strong, nonatomic) UILabel *labelLocation;
7
8
@end
1
#import "MTLocationCell.h"

2
3
#define kMTButtonDeleteWidth 44.0

4
5
#define kMTLabelLocationMarginLeft 44.0

6
7
@implementation MTLocationCell
8
9
#pragma mark -

10
#pragma mark Initialization

11
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
12
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
13
14
    if (self) {
15
        // Helpers

16
        CGSize size = self.contentView.frame.size;
17
18
        // Initialize Delete Button

19
        self.buttonDelete = [UIButton buttonWithType:UIButtonTypeCustom];
20
21
        // Configure Delete Button

22
        [self.buttonDelete setFrame:CGRectMake(0.0, 0.0, kMTButtonDeleteWidth, size.height)];
23
        [self.buttonDelete setImage:[UIImage imageNamed:@"button-delete-location-cell"] forState:UIControlStateNormal];
24
        [self.buttonDelete setImage:[UIImage imageNamed:@"button-delete-location-cell"] forState:UIControlStateSelected];
25
        [self.buttonDelete setImage:[UIImage imageNamed:@"button-delete-location-cell"] forState:UIControlStateDisabled];
26
        [self.buttonDelete setImage:[UIImage imageNamed:@"button-delete-location-cell"] forState:UIControlStateHighlighted];
27
        [self.buttonDelete setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin)];
28
        [self.contentView addSubview:self.buttonDelete];
29
30
        // Initialize Location Label

31
        self.labelLocation = [[UILabel alloc] initWithFrame:CGRectMake(kMTLabelLocationMarginLeft, 0.0, size.width - kMTLabelLocationMarginLeft, size.height)];
32
33
        // Configure Text Label

34
        [self.labelLocation setTextColor:kMTColorGray];
35
        [self.labelLocation setBackgroundColor:[UIColor clearColor]];
36
        [self.labelLocation setFont:[UIFont fontWithName:@"GillSans" size:20.0]];
37
        [self.labelLocation setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin)];
38
        [self.contentView addSubview:self.labelLocation];
39
    }
40
41
    return self;
42
}
43
44
@end

Langkah 3: Memperbarui protokol sumber Data tampilan tabel

Untuk menerapkan desain, kita perlu untuk memperbarui protokol UITableViewDataSource dan UITableViewDelegate. Mulai dengan mengimpor file header kelas MTLocationCell dan kategori di NSUserDefaults yang kita buat sebelumnya. Tampilan tabel akan berisi tiga jenis sel dan perlu kita menyatakan kembali pengidentifikasi untuk setiap jenis (lihat bawah).

1
#import "MTLocationsViewController.h"

2
3
#import "MTLocationCell.h"

4
#import "NSUserDefaults+Helpers.h"

5
6
@interface MTLocationsViewController ()
7
8
@property (strong, nonatomic) NSMutableArray *locations;
9
10
@end
1
static NSString *AddLocationCell = @"AddLocationCell";
2
static NSString *LocationCell = @"LocationCell";
3
static NSString *SettingsCell = @"SettingsCell";

Di setupView, kami mengkonfigurasi tampilan tabel oleh (1) mengatur properti separatorStyle ke UITableViewCellSeparatorStyleNone dan (2) pendaftaran kelas untuk setiap pengenal kembali.

1
- (void)setupView {
2
    // Setup Table View

3
    [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
4
5
    // Register Class for Cell Reuse

6
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:AddLocationCell];
7
    [self.tableView registerClass:[MTLocationCell class] forCellReuseIdentifier:LocationCell];
8
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:SettingsCell];
9
}

UITableViewDataSource protokol perubahan signifikan dan implementasi berbagai metode dapat tampak menakutkan pada awalnya. Sebagian besar kompleksitas, namun, adalah karena bersarang jika pernyataan.

1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
2
    return 2;
3
}
4
5
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
6
    if (section == 0) {
7
        return [self.locations count] + 1;
8
    }
9
10
    return 2;
11
}

Kami juga menerapkan tableView:titleForHeaderInSection: dan tableView:viewForHeaderInSection: untuk menggantikan header Bagian default dengan desain kustom yang cocok desain aplikasi. Ketika mengimplementasikan tableView:viewForHeaderInSection:, penting untuk juga menerapkan tableView:heightForHeaderInSection:.

1
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
2
    switch (section) {
3
        case 0: {
4
            return NSLocalizedString(@"Locations", nil);
5
            break;
6
        }
7
        default: {
8
            return NSLocalizedString(@"Temperature", nil);
9
            break;
10
        }
11
    }
12
13
    return nil;
14
}
15
16
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
17
    // Header Text

18
    NSString *text = [self tableView:tableView titleForHeaderInSection:section];
19
20
    // Helpers

21
    CGRect labelFrame = CGRectMake(12.0, 0.0, tableView.bounds.size.width, 44.0);
22
23
    // Initialize Label

24
    UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
25
26
    // Configure Label

27
    [label setText:text];
28
    [label setTextColor:kMTColorOrange];
29
    [label setFont:[UIFont fontWithName:@"GillSans" size:20.0]];
30
    [label setBackgroundColor:[UIColor clearColor]];
31
32
    // Initialize View

33
    UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, tableView.bounds.size.width, 34.0)];
34
    [backgroundView setBackgroundColor:[UIColor clearColor]];
35
    [backgroundView addSubview:label];
36
37
    return backgroundView;
38
}
39
40
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
41
    return 40.0;
42
}

Kami membuat menggunakan tableView:heightForFooterInSection: untuk membuat beberapa spasi antara bagian atas dan bawah. Ini berarti bahwa kita juga perlu untuk mengimplementasikan tableView:viewForFooterInSection:.

1
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
2
    // Initialize View

3
    UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, tableView.bounds.size.width, 34.0)];
4
    [backgroundView setBackgroundColor:[UIColor whiteColor]];
5
6
    return backgroundView;
7
}
8
9
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
10
    if (section == 0) {
11
        return 40.0;
12
    }
13
14
    return 0.0;
15
}

Pelaksanaan tableView:cellForRowAtIndexPath: agak lebih kompleks karena jenis tiga sel dalam tampilan tabel.

1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
2
    UITableViewCell *cell = nil;
3
4
    if (indexPath.section == 0) {
5
        if (indexPath.row == 0) {
6
            cell = [tableView dequeueReusableCellWithIdentifier:AddLocationCell forIndexPath:indexPath];
7
        } else {
8
            cell = [tableView dequeueReusableCellWithIdentifier:LocationCell forIndexPath:indexPath];
9
        }
10
11
    } else {
12
        cell = [tableView dequeueReusableCellWithIdentifier:SettingsCell forIndexPath:indexPath];
13
    }
14
15
    // Configure Cell

16
    [self configureCell:cell atIndexPath:indexPath];
17
18
    return cell;
19
}

Dalam configureCell:atIndexPath:, kita mengkonfigurasi setiap sel. Seperti yang saya tulis sebelumnya, kompleksitas adalah terutama karena bersarang jika pernyataan. Menekan tombol delete di sel lokasi mengirim pesan deleteLocation: ke lokasi Lihat controller. Kami akan menerapkan deleteLocation: segera.

1
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
2
    // Helpers

3
    UIFont *fontLight = [UIFont fontWithName:@"GillSans-Light" size:18.0];
4
    UIFont *fontRegular = [UIFont fontWithName:@"GillSans" size:18.0];
5
6
    // Background View Image

7
    UIImage *backgroundImage = [[UIImage imageNamed:@"background-location-cell"] resizableImageWithCapInsets:UIEdgeInsetsMake(10.0, 0.0, 0.0, 10.0)];
8
9
    // Configure Table View Cell

10
    [cell.textLabel setFont:fontLight];
11
    [cell.textLabel setTextColor:kMTColorGray];
12
    [cell.textLabel setBackgroundColor:[UIColor clearColor]];
13
    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
14
15
    if (indexPath.section == 0) {
16
        if (indexPath.row == 0) {
17
            [cell.textLabel setText:@"Add Current Location"];
18
            [cell.imageView setContentMode:UIViewContentModeCenter];
19
            [cell.imageView setImage:[UIImage imageNamed:@"icon-add-location"]];
20
21
            // Background View Image

22
            backgroundImage = [[UIImage imageNamed:@"background-add-location-cell"] resizableImageWithCapInsets:UIEdgeInsetsMake(10.0, 0.0, 0.0, 10.0)];
23
24
        } else {
25
            // Fetch Location

26
            NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)];
27
28
            // Configure Cell

29
            [[(MTLocationCell *)cell buttonDelete] addTarget:self action:@selector(deleteLocation:) forControlEvents:UIControlEventTouchUpInside];
30
            [[(MTLocationCell *)cell labelLocation] setText:[NSString stringWithFormat:@"%@, %@", location[MTLocationKeyCity], location[MTLocationKeyCountry]]];
31
        }
32
33
    } else {
34
        if (indexPath.row == 0) {
35
            [cell.textLabel setText:NSLocalizedString(@"Fahrenheit", nil)];
36
37
            if ([NSUserDefaults isDefaultCelcius]) {
38
                [cell.textLabel setFont:fontLight];
39
                [cell.textLabel setTextColor:kMTColorGray];
40
            } else {
41
                [cell.textLabel setFont:fontRegular];
42
                [cell.textLabel setTextColor:kMTColorGreen];
43
            }
44
45
        } else {
46
            [cell.textLabel setText:NSLocalizedString(@"Celsius", nil)];
47
48
            if ([NSUserDefaults isDefaultCelcius]) {
49
                [cell.textLabel setFont:fontRegular];
50
                [cell.textLabel setTextColor:kMTColorGreen];
51
            } else {
52
                [cell.textLabel setFont:fontLight];
53
                [cell.textLabel setTextColor:kMTColorGray];
54
            }
55
        }
56
    }
57
58
    if (backgroundImage) {
59
        // Background View

60
        UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.frame.size.width, cell.frame.size.height)];
61
        [backgroundView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
62
        [backgroundView setImage:backgroundImage];
63
        [cell setBackgroundView:backgroundView];
64
    }
65
}

Karena lokasi sekarang dapat dihapus dengan menekan tombol delete di lokasi sel, baris sendiri tidak lagi perlu untuk dapat diedit. Ini berarti bahwa pelaksanaan tableView:canEditRowAtIndexPath: dapat dikurangi untuk kembali tidak ada dan pelaksanaan tableView:commitEditingStyle:forRowAtIndexPath: dapat dihilangkan sama sekali.

1
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
2
    return NO;
3
}

Langkah 4: Memperbarui protokol delegasi Lihat tabel

Dalam tableView:didSelectRowAtIndexPath:, kita menambahkan sedikit lebih kompleksitas karena masuknya bagian kedua berisi pengaturan suhu. Berkat kategori kami di NSUserDefaults, implementasi sederhana dan ringkas.

1
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
2
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
3
4
    if (indexPath.section == 0) {
5
        if (indexPath.row == 0) {
6
            // Notify Delegate

7
            [self.delegate controllerShouldAddCurrentLocation:self];
8
9
        } else {
10
            // Fetch Location

11
            NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)];
12
13
            // Notify Delegate

14
            [self.delegate controller:self didSelectLocation:location];
15
        }
16
17
    } else {
18
        if (indexPath.row == 0 && [NSUserDefaults isDefaultCelcius]) {
19
            [NSUserDefaults setDefaultToFahrenheit];
20
        } else if (![NSUserDefaults isDefaultCelcius]) {
21
            [NSUserDefaults setDefaultToCelcius];
22
        }
23
24
        // Update Section

25
        [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
26
    }
27
28
    // Show Center View Controller

29
    [self.viewDeckController closeLeftViewAnimated:YES];
30
}

Baris dalam Chris's desain sedikit lebih tinggi daripada ketinggian standar 44 poin. Untuk memasukkan detail ini ke dalam praktek, kami menerapkan tableView:heightForRowAtIndexPath: seperti yang ditunjukkan di bawah ini.

1
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
2
    return 50.0;
3
}

Langkah 5: Menghapus lokasi (Revisited)

Hal terakhir yang perlu kita lakukan adalah menerapkan deleteLocation: metode yang dipanggil ketika tombol Hapus disadap dalam sel lokasi. Implementasi lebih verbose daripada yang mungkin Anda harapkan. Dalam menyimpulkan nomor baris dari sel yang milik tombol Hapus tidak sepele sebagaimana mestinya. Namun, setelah kita memiliki jalan indeks sel yang tombol milik, kita hanya perlu memperbarui array lokasi, memperbarui pengguna default database, dan memperbarui tampilan tabel.

1
- (void)deleteLocation:(id)sender {
2
    UITableViewCell *cell = (UITableViewCell *)[[(UIButton *)sender superview] superview];
3
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
4
5
    // Update Locations

6
    [self.locations removeObjectAtIndex:(indexPath.row - 1)];
7
8
    // Update User Defaults

9
    [[NSUserDefaults standardUserDefaults] setObject:self.locations forKey:MTRainUserDefaultsLocations];
10
11
    // Update Table View

12
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
13
}

5. sentuhan akhir

Untuk menyelesaikan proyek kami, kita perlu mengganti gambar peluncuran default dengan yang diberikan oleh Chris Carey. Peluncuran gambar juga disertakan dalam file sumber dari artikel ini.

Membangun dan menjalankan aplikasi untuk melihat hasil akhir dalam tindakan. Meskipun kami telah menghabiskan beberapa waktu menciptakan dan merancang aplikasi, masih ada beberapa tepi kasar. Ini juga akan bagus untuk mengimplementasikan mekanisme cache sehingga kita dapat menunjukkan data cache ke pengguna selama permintaan ke API ramalan belum kembali. Berikut adalah beberapa contoh dari penyempurnaan yang kita dapat menambahkan ke aplikasi kita.

Kesimpulan

Menciptakan antarmuka pengguna cukup sedikit pekerjaan, tapi kode terlibat tidak semua yang rumit. Saya berharap tutorial ini telah menunjukkan Anda desain besar apa yang bisa lakukan untuk aplikasi. Aplikasi konsumen khususnya benar-benar manfaat dari desain yang menarik, segar seperti yang kita gunakan dalam tutorial ini.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.