iOS SDK: Erstellen einer benutzerdefinierten Text Input View
German (Deutsch) translation by Władysław Łucyszyn (you can also view the original English article)
Eine tolle Anwendung zu entwickeln ist keine einfache Aufgabe. Traditionell war einer der schwierigsten Aspekte dabei die Erstellung reichhaltiger, überzeugender Benutzeroberflächen. In diesem Tutorial erfahren Sie, wie Sie eine benutzerdefinierte Text Input View erstellen, die Ihre eigenen Apps zum Leuchten bringt!
Tutorial-Vorschau
Serienübersicht
Dieses Tutorial ist das erste in einer Sammlung zum Erstellen benutzerdefinierter Oberflächenelemente. In diesem Tutorial werden wir benutzerdefinierte Text Input View behandeln, und in den nächsten beiden Tutorials werden wir benutzerdefinierte Accordion-Menüs und Alert-Views behandeln. Das Serienformat ist wie folgt:
- Erstellen einer benutzerdefinierten Text Input View
- Erstellen eines benutzerdefinierten Accordion-Menüs (Anstehende Veröffentlichung)
- Erstellen einer benutzerdefinierten Alert View (Anstehende Veröffentlichung)
In diesem Tutorial werden wir eine einfache Listenanwendung erstellen, die einige grundlegende Funktionen enthält. In diesem Beispiel kann unsere App Elemente nur mithilfe unserer brandneuen benutzerdefinierten Text Input View hinzufügen und bearbeiten. Das letzte Projekt dieses Tutorials wird die Basis für das nächste sein, bei dem wir ein Accordion-Menü erstellen werden, um dem Benutzer einige Optionen zur Verfügung zu stellen. Im dritten und letzten Tutorial verwenden wir das letzte Projekt des zweiten Tutorials, um eine benutzerdefinierte Alert-View zu erstellen.
1. Erstellen des Projekts
Beginnen Sie mit dem Starten von Xcode und erstellen Sie eine Single View-Anwendung:



Fahren Sie fort und legen Sie einen Namen für das Projekt fest. Ich habe meine CustomViewsDemo genannt. Stellen Sie sicher, dass Sie auch die Option Automatische Referenzzählung verwenden aktivieren:



Wählen Sie abschließend einen Ordner zum Speichern des Projekts aus und klicken Sie auf Erstellen:



2. Einrichten der Schnittstelle
Schritt 1
Klicken Sie auf die Datei ViewController.xib, damit der Interface Builder auf dem Bildschirm angezeigt wird. Deaktivieren Sie zuerst die Autolayout-Option (wir tun dies, damit dieses Demoprojekt auf iOS älter als 6 funktioniert - Autolayout ist eine iOS 6-Funktion):
- Klicken Sie auf die Schaltfläche Dienstprogramme in der Xcode-Symbolleiste, um den Bereich Dienstprogramme anzuzeigen, falls dieser nicht sichtbar ist.
- Klicken Sie auf den Dateiinspektor.
- Scrollen Sie ein wenig nach unten und klicken Sie auf die Option Autolayout verwenden, um sie auszuschalten.

Schritt 2
Klicken Sie nun auf den Attributes Inspector und setzen Sie im Abschnitt Simulated Metrics den Size-Wert auf None, damit er auch auf einem 3,5"-Bildschirm funktioniert.

Schritt 3
Fügen Sie der Ansicht eine UIToolBar hinzu und platzieren Sie sie am unteren Rand der Ansicht. Machen Sie Folgendes:
- Fügen Sie ein flexibles Leertaste-Schaltflächenelement links neben dem Standardleisten-Schaltflächenelement hinzu, um zu erzwingen, dass es auf der rechten Seite der Symbolleiste bleibt.
- Setzen Sie den Titel des Elements der Leiste auf Element hinzufügen.
- Stellen Sie die Tönungsfarbe der Taste ein auf: (R: 51, G: 51, B: 51).
- Stellen Sie die Tönungsfarbe der Symbolleiste auf (R: 0, G: 0, B: 51).
Schritt 4
Fügen Sie als Nächstes eine UITableView innerhalb des verbleibenden verfügbaren Speicherplatzes der Ansicht hinzu. Setzen Sie den Stil auf Gruppiert und das Trennzeichen auf Single Line:

Stellen Sie außerdem die Hintergrundfarbe auf (R: 51, G: 51, B: 51). Ihre Oberfläche sollte nun so aussehen:



3. IBOutlet-Eigenschaften und IBAction-Methoden
Bevor wir weitermachen, müssen wir die UITableView mit einer IBOutlet-Eigenschaft verbinden und eine IBAction-Methode für das Symbolleisten-Schaltflächenelement (die Schaltfläche "Element hinzufügen") erstellen. Klicken Sie dazu im Interface Builder auf die Mitte Schaltfläche des Editor-Bereichs in der Xcode-Symbolleiste, um den Assistenten-Editor anzuzeigen:

Schritt 1
Um eine neue IBOutlet-Eigenschaft einzufügen, Strg+Klick (Rechtsklick) auf die Tabellenansicht > Klicken Sie auf das neue referenzierende Outlet > Ziehen und ablegen in den Assistenteneditor.



Geben Sie als Nächstes einen Namen für die neue Eigenschaft an. Ich habe es einfach table genannt.

Schritt 2
Um eine IBA-Aktion für das Balkenschaltflächenelement zu erstellen, Strg+Klick (Rechtsklick) auf das Balkenschaltflächenelement > Klicken Sie auf die Option Selektor im Abschnitt Gesendete Aktionen > Ziehen Sie sie in den Assistenteneditor:



Legen Sie einen Namen für die Methode fest. Ich habe mein addItem genannt.

4. UITableView-Methoden
Schritt 1
In diesem Schritt müssen wir die minimal erforderlichen Tabellenansichtsmethoden implementieren, damit unsere Tabelle ordnungsgemäß funktioniert. Zuvor müssen wir jedoch den Ansichtscontroller als Delegat und Datenquelle für die Tabellenansicht festlegen.
Klicken Sie auf die Datei ViewController.h. Bilden Sie den @interface-Header wie folgt:
1 |
@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> |
Fügen Sie dann in der Datei ViewController.m und in der Methode viewDidLoad Folgendes hinzu:
1 |
// Set the tableview's delegate and datasource.
|
2 |
[_table setDelegate:self]; |
3 |
[_table setDataSource:self]; |
Schritt 2
Ein NSMutableArray-Array ist die Quelle unserer Listenelemente (der Inhalt der Tabelle). Zuerst müssen wir es jedoch deklarieren und initialisieren. Gehen Sie in der Datei ViewController.m an den Anfang und fügen Sie im privaten Teil des @interface die nächste Zeile hinzu:
1 |
@interface ViewController () |
2 |
|
3 |
@property (nonatomic, strong) NSMutableArray *sampleDataArray; |
4 |
|
5 |
@end
|
Auch innerhalb von viewDidLoad:
1 |
// Initialize the sample data array.
|
2 |
_sampleDataArray = [[NSMutableArray alloc] init]; |
Schritt 3
Lassen Sie uns nun einige Methoden der Tabellenansicht implementieren. Wir beginnen mit der Anzahl der Abschnitte:
1 |
-(int)numberOfSectionsInTableView:(UITableView *)tableView{ |
2 |
// Set the number of sections inside the tableview. We need only one section.
|
3 |
return 1; |
4 |
}
|
Als nächstes legen Sie die Gesamtanzahl der Zeilen fest. Diese Zahl entspricht der Gesamtzahl der im Array _sampleDataArray vorhandenen Objekte.
1 |
-(int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ |
2 |
// The number of rows is equal to the number of the sample data in our tableview.
|
3 |
return [_sampleDataArray count]; |
4 |
}
|
Legen wir die Höhe jeder Zeile fest:
1 |
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ |
2 |
// Set the row height.
|
3 |
return 45.0; |
4 |
}
|
Jetzt richten wir unsere Zellen ein. Im Code finden Sie alle Anpassungen für die Zellen. Es gibt Kommentare, die fast alles erklären. Sie können nach Belieben ändern, was Sie möchten:
1 |
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ |
2 |
static NSString *CellIdentifier = @"Cell"; |
3 |
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; |
4 |
if (cell == nil) { |
5 |
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; |
6 |
|
7 |
// Let's set some custom cell options.
|
8 |
// Set the cell's background.
|
9 |
[cell setBackgroundColor:[UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0]]; |
10 |
|
11 |
// Set the selection style.
|
12 |
[cell setSelectionStyle:UITableViewCellSelectionStyleGray]; |
13 |
|
14 |
// Set the accessory type.
|
15 |
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; |
16 |
|
17 |
// Set a font for the cell's textlabel.
|
18 |
[[cell textLabel] setFont:[UIFont fontWithName:@"Georgia" size:15.0]]; |
19 |
}
|
20 |
|
21 |
[[cell textLabel] setText:[_sampleDataArray objectAtIndex:[indexPath row]]]; |
22 |
|
23 |
return cell; |
24 |
}
|
Fügen Sie schließlich die -(void)tableView:didSelectRowAtIndexPath: Delegate-Methode hinzu:
1 |
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ |
2 |
|
3 |
}
|
Lassen Sie diese Methode jetzt leer. Wir werden es später wieder besuchen.
Zusammenfassend haben wir unser Projekt erstellt und die Schnittstelle mit dem Interface Builder eingerichtet. Wir haben die erforderliche IBOutlet-Eigenschaft und die IBAction-Methode verbunden und die minimal erforderlichen Methoden implementiert, damit unsere Tabelle (unsere Liste) richtig funktioniert. Fahren wir mit der Erstellung der benutzerdefinierten Texteingabe fort. Wir werden gleich auf den ViewController zurückkommen.
5. Benutzerdefinierter Text Input View-Controller
Bei der Entwicklung von Projekten ist es eine schöne Angewohnheit, alles ordentlich und in Ordnung zu halten. Aus diesem Grund werden wir eine neue Gruppe (einen virtuellen Ordner) für den Text Input View-Controller erstellen.
Schritt 1
Klicken Sie im Projektnavigator-Bereich auf der linken Seite von Xcode Strg+Klick (Rechtsklick) auf die CustomViewsDemo-Gruppe > Wählen Sie die Option Neue Gruppe aus dem Popup-Menü:

Benennen Sie die neue Gruppe Custom Text Input View:

Schritt 2
Jetzt können wir den neuen View Controller hinzufügen. Strg+Klick (Rechtsklick) auf die CustomViewsDemo-Gruppe > Wählen Sie die Option Neue Datei... aus dem Popup-Menü:



Wählen Sie als Vorlage für die neue Datei die Klasse Objective-C aus und klicken Sie auf Weiter.



Geben Sie im Feld Klasse den Namen CustomTextInputViewController ein und stellen Sie sicher, dass im Feld Unterklasse von der Wert UIViewController ausgewählt ist. Vergessen Sie auch nicht, die Option Mit XIB für die Benutzeroberfläche aktiviert zu setzen:



Klicken Sie abschließend auf die Schaltfläche Erstellen. Stellen Sie sicher, dass die Custom Text Input View die ausgewählte Gruppe ist, wie in der folgenden Abbildung gezeigt:



6. Benutzeroberfläche der Text Input View
Schritt 1
Klicken Sie auf die Datei CustomTextInputViewController.xib, um den Interface Builder anzuzeigen und die Schnittstelle einzurichten. Mach Folgendes:
- Deaktivieren Sie wie zuvor die Option Autolayout (Dienstprogramme-Fenster > Dateiinspektor > Klicken Sie auf das Kontrollkästchen Autolayout verwenden).
- Klicken Sie auf den Attributes Inspector und ändern Sie im Abschnitt Simulierte Metriken die Größe auf None.
Schritt 2
Jetzt ist es an der Zeit, die gewünschten Unteransichten zu unserer Ansicht hinzuzufügen. Fügen Sie die nächsten Unteransichten hinzu und legen Sie ihre Eigenschaften wie beschrieben fest:
- UILabel
- Rahmen: X: 0,0, Y: 145,0, Breite: 320,0, Höhe: 30
- Schriftart: Georgia, 17.0
- Farbe: Schwarz
- Ausrichtung: Mitte
- Hintergrundfarbe: (R: 204, G: 204, B: 204)
- UITextField
- Rahmen: X: 0,0, Y: 180,0, Breite: 320,0, Höhe: 30,0
- Schriftart: Georgia, 15.0
- Farbe: Schwarz
- Rahmenstil: Lünette
- Clear-Button: Erscheint während der Bearbeitung
- Großschreibung: Sätze
- Return-Taste: Fertig
- Hintergrundfarbe: Weiß
Die meisten dieser Einstellungen werden im nächsten Bild angezeigt:

- UIToolBar
- Rahmen: X: 0,0, Y: 225,0, Breite: 320,0, Höhe: 44,0
- Tönungsfarbe: (R: 204, G: 204, B: 204)
Beachten Sie, dass der Y-Punkt im Moment nicht wichtig ist, da er programmgesteuert für jede Unteransicht festgelegt wird.
Schritt 3
Abgesehen von den oben genannten fügen Sie die folgenden UIBarButton-Elemente zur Symbolleiste neben dem Standardelement für die Leiste hinzu:
- Ein flexibles Leertaste-Element
- Ein weiteres Element der Leiste
Wählen Sie beide Elemente der Leiste aus (nicht das flexible Leerzeichen) und stellen Sie ihre Farbe auf (R: 51, G: 51, B: 51). Setzen Sie für die Schaltfläche der linken Leiste den Titel auf Okay. Setzen Sie für die rechte Leistenschaltfläche den Titel auf Abbrechen.
Wählen Sie schließlich alle drei Unteransichten (UILabel, UITextField und UIToolBar) aus und legen Sie die Werte für die automatische Größenanpassung wie unten gezeigt fest (Flexible Breite, Flexibler rechter Rand, Flexibler linker Rand und Flexibler unterer Rand):



7. IBOutlets und IBActions
Ich habe Ihnen zuvor gezeigt, wie Sie IBOutlet-Eigenschaften und IBAction-Methoden erstellen und mit Unteransichten verbinden. Folgen Sie der gleichen Methode wie oben beschrieben, erstellen und verbinden Sie die nächsten Eigenschaften mit UILabel, UITextField bzw. UIToolbar:
1 |
@property (weak, nonatomic) IBOutlet UILabel *lblTitle; |
2 |
@property (weak, nonatomic) IBOutlet UITextField *txtText; |
3 |
@property (weak, nonatomic) IBOutlet UIToolbar *toolbarIAV; |
Gehen Sie dann zum Deklarieren und Verbinden der nächsten IBAction-Methoden mit den Schaltflächen Okay und Cancel:
1 |
- (IBAction)acceptTextChanges:(id)sender; |
2 |
- (IBAction)cancelTextChanges:(id)sender; |
An dieser Stelle ist unsere Arbeit mit dem Interface Builder beendet. Es ist an der Zeit, das Verhalten zu codieren, das wir von der Text Input View benötigen.
8. Codierung
Schritt 1
Zuerst müssen wir eine Art Einrichtung im Code vornehmen, bevor wir eine Methode implementieren. Wir beginnen damit, den View-Controller als Delegaten für das Textfeld festzulegen. Klicken Sie auf die Datei CustomTextInputViewController.h und ändern Sie den @interface-Header entsprechend:
1 |
@interface CustomTextInputViewController : UIViewController <UITextFieldDelegate> |
Wechseln Sie als Nächstes zur Datei CustomTextInputViewController.m und legen Sie in der viewDidLoad-Methode den Delegaten fest:
1 |
// Set the textfield delegate.
|
2 |
[_txtText setDelegate:self]; |
Legen Sie außerdem innerhalb von viewDidLoad die UIToolbar (das ToolbarIAV) als Input Accessory View des Textfelds fest:
1 |
// Set the textfield delegate.
|
2 |
[_txtText setDelegate:self]; |
3 |
|
4 |
// Set the input accessory view of the textfield.
|
5 |
[_txtText setInputAccessoryView:_toolbarIAV]; |
So weit, ist es gut. Zu Beginn dieses Tutorials habe ich erwähnt, dass die Ansicht des View-Controllers als Abdeckung dient, um zu verhindern, dass Benutzer auf etwas anderes tippen, das sich hinter unserer Ansicht befindet. Wir brauchen es auch halbtransparent, damit es gut aussieht. Gehen Sie daher und fügen Sie die nächste Zeile hinzu, die unsere Ansicht konfiguriert:
1 |
// Set the background color of the view to a semi-transparent gray.
|
2 |
[self.view setBackgroundColor:[UIColor colorWithRed:0.66 |
3 |
green:0.66 |
4 |
blue:0.66 |
5 |
alpha:0.75]]; |
Denken wir jetzt darüber nach. Wie eingangs erwähnt, muss das Textfeld direkt über der Eingabezubehöransicht (der Symbolleiste) und die Titelbeschriftung über dem Textfeld erscheinen. Um dieses Layout zu erreichen, müssen wir den Ursprung der Tastatur und der Eingabezubehöransicht kennen, damit wir das Textfeld und die Beschriftung entsprechend anpassen können. Aber woher wissen wir, wann die Tastatur erscheint und wie erhalten wir ihre Größe oder ihren Ursprung?
Nun, die Antwort ist einfach. Jedes Mal, wenn die Tastatur angezeigt wird, sendet iOS eine Benachrichtigung mit dem Namen UIKeyboardWillShowNotification (eigentlich sendet iOS mehr Benachrichtigungen, aber wir kümmern uns derzeit nicht um sie). Wir werden den View Controller als Beobachter für diese Benachrichtigung hinzufügen und wenn sie eintrifft, wird eine vordefinierte Methode (von uns) aufgerufen. Fügen Sie in diesem Sinne die nächste Zeile wieder in die viewDidLoad-Methode ein:
1 |
// Add self as observer to the NSNotificationCenter so we know when the keyboard is about to be shown up.
|
2 |
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowWithNotification:) name:UIKeyboardWillShowNotification object:nil]; |
Beachten Sie, dass keyboardWillShowWithNotification: eine Methode ist, die wir in Kürze implementieren werden.
Ein weiterer Punkt, den wir berücksichtigen sollten, ist die Statusleiste. Die Position, an der unsere Unteransichten erscheinen, hängt von der Statusleiste und ihrer Höhe ab. Daher wäre es eine gute Idee, wenn wir eine Variable hätten, die den von der Statusleiste erzeugten Offset (ihre Höhe) beibehält, wenn sie sichtbar ist.
Gehen Sie zum Anfang der Datei und deklarieren Sie im privaten Teil der @interface eine CGFloat-Variable, die den Offset der Statusleiste darstellt. Dazu deklarieren Sie die keyboardWillShowWithNotification: Ich habe es etwas früher erwähnt:
1 |
@interface CustomTextInputViewController (){ |
2 |
CGFloat statusBarOffset; |
3 |
}
|
4 |
|
5 |
-(void)keyboardWillShowWithNotification:(NSNotification *)notification; |
6 |
|
7 |
@end
|
Ich werde bald mehr über die Statusleiste erwähnen.
Schritt 2
Jetzt können wir mit der Implementierungsphase fortfahren und die erforderlichen öffentlichen Methoden erstellen, auf die andere Klassen zugreifen können. Wechseln Sie zur Datei CustomTextInputViewController.h und deklarieren Sie die folgenden drei Methoden:
1 |
-(void)showCustomTextInputViewInView:(UIView *)targetView |
2 |
withText:(NSString *)text |
3 |
andWithTitle:(NSString *)title; |
4 |
-(void)closeTextInputView; |
5 |
-(NSString *)getText; |
Es sollte klar sein, was jede Methode bewirkt.
Beginnen wir mit der Methode showCustomTextInputViewInView:withText:andWithTitle. Bevor wir mit dem Codieren beginnen, gibt es einige Punkte, die ich erwähnen sollte. Zunächst müssen wir prüfen, ob die Statusleiste sichtbar ist oder nicht und den Wert statusBarOffset entsprechend setzen. Wir können leicht herausfinden, ob es sichtbar ist und seine Größe ermitteln. Es gibt jedoch eine kleine Falle, falls die Statusleiste sichtbar ist und wir uns sowohl mit Hoch- als auch Querformat auseinandersetzen müssen. Im Hochformat hat die Statusleistengröße die Form Breite x Höhe (z. B. 320,0 x 20,0). Im Querformat hat die Größe die Form Höhe x Breite (z. B. 20,0 x 480,0). Am einfachsten ermitteln wir die Höhe der Statusleiste, indem wir den Mindestwert zwischen Breite und Höhe prüfen. Mit dieser Methode ist es sicher, dass wir den richtigen Wert erhalten. Fügen Sie diese direkt danach in das folgende Code-Snippet ein.
Außerdem erinnern Sie sich vielleicht daran, dass wir die Autolayout-Funktion deaktiviert haben, sodass wir dafür verantwortlich sind, unsere Ansichten in allen Ausrichtungen korrekt darzustellen. Das bedeutet, dass wir bei jedem Aufruf dieser Methode die Ausrichtung überprüfen und den Rahmen der Ansicht entsprechend einstellen müssen. Es ist wichtig zu beachten, dass im Querformat die Breite des Bildschirms die Höhe für die Ansicht und die Höhe des Bildschirms die Breite für die Ansicht ist. Auch weil die Statusleiste sichtbar ist, entsteht im Querformat am linken Rand der Ansicht ein Padding, der beseitigt werden muss. Aus diesem Grund haben wir früher die Variable statusBarOffset deklariert.
Schließlich möchten wir, dass unsere Sicht zu Beginn nicht sichtbar ist und Animationen reibungslos in den Bildschirm gleiten.
Aber lassen Sie uns zuerst alles in Aktion sehen. Öffnen Sie die CustomTextInputViewController.m und implementieren Sie die Methode:
1 |
-(void)showCustomTextInputViewInView:(UIView *)targetView withText:(NSString *)text andWithTitle:(NSString *)title{ |
2 |
if (![[UIApplication sharedApplication] isStatusBarHidden]) { |
3 |
CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size; |
4 |
if (statusBarSize.width < statusBarSize.height) { |
5 |
// If the width is smaller than the height then this is the value we need.
|
6 |
statusBarOffset = statusBarSize.width; |
7 |
}
|
8 |
else{ |
9 |
// Otherwise the height is the desired value we want to keep.
|
10 |
statusBarOffset = statusBarSize.height; |
11 |
}
|
12 |
}
|
13 |
else{ |
14 |
// Otherwise set it to 0.0.
|
15 |
statusBarOffset = 0.0; |
16 |
}
|
17 |
|
18 |
// Before showing the self.view on-screen, we need to calculate the following
|
19 |
// values, depending always on the orientation.
|
20 |
CGFloat x, width, height; |
21 |
|
22 |
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || |
23 |
[[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight){ |
24 |
|
25 |
// Landscape orientation.
|
26 |
|
27 |
// Set the x point for the view. If we don't substract the statusBarOffset value then a
|
28 |
// padding is going to exist at the left of the view when it will appear.
|
29 |
x = targetView.frame.origin.x - statusBarOffset; |
30 |
|
31 |
// In landscape orientation, the width of the view equals to the height of the target view.
|
32 |
width = targetView.frame.size.height; |
33 |
// The same with the height.
|
34 |
height = targetView.frame.size.width; |
35 |
}
|
36 |
else{ |
37 |
// In portrait orientation everything is normal.
|
38 |
x = targetView.frame.origin.x; |
39 |
width = targetView.frame.size.width; |
40 |
height = targetView.frame.size.height; |
41 |
}
|
42 |
|
43 |
// Initially set the self.view off screen. That's why the y point equals to -height.
|
44 |
[self.view setFrame:CGRectMake(x, |
45 |
-height, |
46 |
width, |
47 |
height)]; |
48 |
|
49 |
// Add the view to the target view.
|
50 |
[targetView addSubview:self.view]; |
51 |
|
52 |
// Begin animating the appearance of the view.
|
53 |
[UIView beginAnimations:@"" context:nil]; |
54 |
[UIView setAnimationDuration:0.25]; |
55 |
[UIView setAnimationCurve:UIViewAnimationCurveLinear]; |
56 |
|
57 |
// We simply want the y point of the origin to become 0.0.
|
58 |
[self.view setFrame:CGRectMake(self.view.frame.origin.x, |
59 |
0.0, |
60 |
self.view.frame.size.width, |
61 |
self.view.frame.size.height)]; |
62 |
[UIView commitAnimations]; |
63 |
|
64 |
// Set the textfield as the first responder to make the keyboard appear.
|
65 |
[_txtText becomeFirstResponder]; |
66 |
|
67 |
// Set the text to edit (if exists) to the textfield.
|
68 |
[_txtText setText:text]; |
69 |
|
70 |
// Set the label's text (the title above the textfield).
|
71 |
[_lblTitle setText:title]; |
72 |
}
|
Die Kommentare innerhalb der Methode erklären alles. Beachten Sie, dass wir darin die Methode becomeFirstResponder des Textfelds _txtText aufrufen, damit auch die Tastatur angezeigt wird. Wir werden gleich sehen, wie wichtig dieser Aufruf ist, denn das ist der entscheidende Punkt, damit unsere Ansichten richtig positioniert werden.
Lassen Sie uns nun die nächste Methode implementieren. Das Schließen der Ansicht ist die entgegengesetzte Aktion zum Anzeigen.
1 |
-(void)closeTextInputView{ |
2 |
// Resign the textfield from first responder to make the keyboard go away.
|
3 |
[_txtText resignFirstResponder]; |
4 |
|
5 |
// Animate the view closing. It's just the opposite from the showing animation.
|
6 |
[UIView beginAnimations:@"" context:nil]; |
7 |
[UIView setAnimationDuration:0.25]; |
8 |
[UIView setAnimationCurve:UIViewAnimationCurveLinear]; |
9 |
[self.view setFrame:CGRectMake(self.view.frame.origin.x, |
10 |
-self.view.frame.size.height, |
11 |
self.view.frame.size.width, |
12 |
self.view.frame.size.height)]; |
13 |
[UIView commitAnimations]; |
14 |
|
15 |
// Also remove the view from the superview after a while (we must let the animation finish first).
|
16 |
[self.view performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:0.25]; |
17 |
}
|
Beachten Sie, dass wir die Ansicht nicht sofort aus der Superansicht entfernt haben, sondern nachdem die Animation beendet ist.
Schließlich die dritte Methode:
1 |
-(NSString *)getText{ |
2 |
// Return the textfield's text.
|
3 |
return [_txtText text]; |
4 |
}
|
Schritt 3
In diesem nächsten Schritt erfahren Sie, wie Sie mit der Tastatur umgehen. Weiter oben im privaten Teil der Schnittstelle haben wir diese Methode deklariert:
1 |
-(void)showCustomTextInputViewInView:(UIView *)targetView withText:(NSString *)text andWithTitle:(NSString *)title; |
Dies ist die Methode, die jedes Mal aufgerufen wird, wenn die Tastatur angezeigt wird und eine UIKeyboardWillShowNotification-Benachrichtigung eintrifft. Jetzt können wir anfangen, daran zu arbeiten. Der notification-Parameter enthält ein NSDictionary mit Informationen zur Tastatur. Ein Teil dieser Informationen ist die Größe und Herkunft der Tastatur. Was wir hier eigentlich brauchen, ist der Ursprungspunkt, denn wenn wir die Y-Koordination der Tastatur kennen (Eingabezubehöransicht enthalten), können wir das Textfeld und die Beschriftung richtig gestalten. Im Querformat ändert es sich erneut und die X-Koordination der Tastatur ist die gewünschte Y-Koordination für unser Textfeld. Hier ist der Code, den Sie benötigen:
1 |
-(void)keyboardWillShowWithNotification:(NSNotification *)notification{ |
2 |
// Get the userInfo dictionary from the notification object.
|
3 |
NSDictionary *info = [notification userInfo]; |
4 |
|
5 |
// Get the keyboard origin.
|
6 |
CGPoint keyboardOrigin = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].origin; |
7 |
|
8 |
CGFloat keyboardOriginY; |
9 |
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || |
10 |
[[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight){ |
11 |
|
12 |
// In landscape orientation the x point represents the vertical axis.
|
13 |
keyboardOriginY = keyboardOrigin.x; |
14 |
}
|
15 |
else{ |
16 |
keyboardOriginY = keyboardOrigin.y; |
17 |
}
|
18 |
|
19 |
// Set the appropriate frame for the textfield. That is just right above the input accessory view.
|
20 |
[_txtText setFrame:CGRectMake(_txtText.frame.origin.x, |
21 |
keyboardOriginY - _txtText.frame.size.height - statusBarOffset, |
22 |
_txtText.frame.size.width, |
23 |
_txtText.frame.size.height)]; |
24 |
|
25 |
// Set the label's frame in turn.
|
26 |
[_lblTitle setFrame:CGRectMake(0.0, |
27 |
_txtText.frame.origin.y - _lblTitle.frame.size.height, |
28 |
_lblTitle.frame.size.width, |
29 |
_lblTitle.frame.size.height)]; |
30 |
|
31 |
}
|
Ich bin sicher, dass Sie die Subtraktion des statusBarOffset im obigen Code bemerkt haben. Wenn wir dies nicht tun, wird das Textfeld unter der Eingabezubehöransicht ausgeblendet.
Schritt 4
In dieser Phase müssen wir an der Protokolldefinition arbeiten. Bis zu diesem Punkt ist der View-Controller fast fertig, aber noch nicht ganz fertig. Was hier fehlt, ist die Protokolldefinition, die es der Delegate-Klasse, die sie übernimmt (in unserem Fall dem ViewController), ermöglicht, die erforderlichen Methoden zu implementieren, die für die Verarbeitung der Schaltflächen Okay und Cancel erforderlich sind.
Gehen Sie zur Datei CustomTextInputViewController.h und definieren Sie ein Protokoll zusammen mit den nächsten Delegate-Methoden:
1 |
@protocol CustomTextInputViewControllerDelegate |
2 |
-(void)shouldAcceptTextChanges; |
3 |
-(void)shouldDismissTextChanges; |
4 |
@end
|
Fügen Sie außerdem direkt nach dem @interface-Header die hervorgehobene Zeile hinzu:
1 |
@interface CustomTextInputViewController : UIViewController |
2 |
@property (nonatomic, strong) id delegate; |
3 |
...
|
4 |
...
|
Gemäß unserer Vorgehensweise sollte die Delegate-Klasse die Methode shouldAcceptTextChanges implementieren, um das Tippen auf die Schaltfläche Okay zu verarbeiten, und die Methode shouldDismissTextChanges, um das Tippen auf die Schaltfläche Cancel zu verarbeiten.
Aber was ist mit den IBAction-Methoden dieser Klasse? Sie sind bis jetzt leer geblieben. Füllen wir sie jetzt aus:
1 |
- (IBAction)acceptTextChanges:(id)sender { |
2 |
[self.delegate shouldAcceptTextChanges]; |
3 |
}
|
4 |
|
5 |
- (IBAction)cancelTextChanges:(id)sender { |
6 |
[self.delegate shouldDismissTextChanges]; |
7 |
}
|
Wie Sie sehen, wird beim Tippen auf die Schaltfläche Okay die Delegatmethode shouldAcceptTextChanges aufgerufen, während beim Tippen auf die Schaltfläche Cancel die Delegatmethode shouldDismissTextChanges aufgerufen wird.
Um ganz richtig zu sein, müssen Sie noch einen weiteren Schritt ausführen: Lassen Sie die Schaltfläche Fertig der Tastatur funktionieren. Dazu müssen wir nur die -(BOOL)textFieldShouldReturn: Delegate-Methode implementieren:
1 |
-(BOOL)textFieldShouldReturn:(UITextField *)textField{ |
2 |
// The tap on the Done button of the keyboard equals to the Okay button.
|
3 |
[self.delegate shouldAcceptTextChanges]; |
4 |
return YES; |
5 |
}
|
Jetzt ist unsere neue benutzerdefinierte Ansicht fertig. Alles, was wir tun müssen, ist es auszuprobieren.
9. Text Input View in Aktion
Schritt 1
Bevor wir sehen, dass unsere neue benutzerdefinierte Text Input View funktioniert, müssen wir noch einige Schritte ausführen. Zunächst sollten wir die ViewController-Klasse als ihren Delegaten deklarieren. Öffnen Sie die Datei ViewController.h, importieren Sie die Datei CustomTextInputViewController.h und machen Sie unsere Klasse zu ihrem Delegaten am Interface-Header:
1 |
#import <UIKit/UIKit.h>
|
2 |
#import "CustomTextInputViewController.h"
|
3 |
|
4 |
@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, CustomTextInputViewControllerDelegate> |
5 |
@property (weak, nonatomic) IBOutlet UITableView *table; |
6 |
...
|
7 |
...
|
Wechseln Sie nun zur Datei ViewController.m und deklarieren Sie im privaten Teil des @interface ein CustomTextInputViewController-Objekt. Ich habe es textInput genannt:
1 |
@interface ViewController () |
2 |
|
3 |
@property (nonatomic, strong) NSMutableArray *sampleDataArray; |
4 |
|
5 |
@property (nonatomic, strong) CustomTextInputViewController *textInput; |
6 |
|
7 |
@end
|
Lassen Sie es uns in der Methode viewDidLoad initialisieren:
1 |
// Initialize the custom text input object.
|
2 |
_textInput = [[CustomTextInputViewController alloc] init]; |
3 |
[_textInput setDelegate:self]; |
Schritt 2
Gehen Sie zur addItem IBAction-Methode, um unsere Text Input View anzuzeigen:
1 |
- (IBAction)addItem:(id)sender { |
2 |
[_textInput showCustomTextInputViewInView:self.view |
3 |
withText:@"" |
4 |
andWithTitle:@"Add new item"]; |
5 |
}
|
Einfach, oder?
Wenn Sie die App jetzt ausführen, sehen Sie die Text Input View in Aktion, aber die Schaltflächen Okay und Abbrechen funktionieren nicht, da wir die Delegate-Methoden noch nicht implementiert haben. Also machen wir es jetzt:
1 |
-(void)shouldAcceptTextChanges{ |
2 |
// Add the new item to the sampleDataArray.
|
3 |
[_sampleDataArray addObject:[_textInput getText]]; |
4 |
|
5 |
// Reload the table using animation.
|
6 |
[_table reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic]; |
7 |
|
8 |
// Close the text input.
|
9 |
[_textInput closeTextInputView]; |
10 |
}
|
11 |
|
12 |
-(void)shouldDismissTextChanges{ |
13 |
[_textInput closeTextInputView]; |
14 |
}
|
Führen Sie es aus und es wird funktionieren. Jeder Text, den Sie in das Textfeld eingeben, wird in der Tabelle angezeigt. Wir sind jedoch noch nicht vollständig bereit, da wir keine Elemente bearbeiten können.
Schritt 3
Es ist an der Zeit, die Delegate-Methode der Tabellenansicht -(void)tableView:didSelectRowAtIndexPath: zu besuchen. Wir möchten, dass jede angetippte Zeile in unserer benutzerdefinierten Text Input View bearbeitet wird. Aber wir müssen auch wissen, wann der Benutzer eine Zeile hinzufügt oder bearbeitet. Aus diesem Grund verwenden wir ein Flag, das anzeigt, ob der Benutzer eine Zeile bearbeitet oder nicht.
Gehen Sie zum privaten Teil des @interface und fügen Sie die folgende Variable hinzu:
1 |
@interface ViewController (){
|
2 |
BOOL isEditingItem; |
3 |
} |
4 |
|
5 |
@property (nonatomic, strong) NSMutableArray *sampleDataArray; |
6 |
|
7 |
@property (nonatomic, strong) CustomTextInputViewController *textInput; |
8 |
|
9 |
@end |
Vergessen Sie nicht die geschweiften Klammern. Setzen Sie nun in der Methode viewDidLoad den Wert auf NO.
1 |
// Set the initial value of the isEditingItem flag.
|
2 |
isEditingItem = NO; |
Wechseln Sie zur Delegate-Methode der Tabelle:
1 |
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ |
2 |
[_textInput showCustomTextInputViewInView:self.view |
3 |
withText:[_sampleDataArray objectAtIndex:[indexPath row]] |
4 |
andWithTitle:@"Edit item"]; |
5 |
|
6 |
// Set the isEditingItem flag value to YES, indicating that
|
7 |
// we are editing an item.
|
8 |
isEditingItem = YES; |
9 |
}
|
Wenn Sie jetzt in der Tabellenansicht auf vorhandene Zeilen tippen, wird die Text Input View angezeigt, um sie zu bearbeiten. Aber egal wie sehr Sie sich bemühen, Ihre Änderungen werden nicht in der bearbeiteten Zeile gespeichert, sondern als neue Zeilen. Das bedeutet, dass wir die Delegate-Methode -(void)shouldAcceptTextChanges als solche leicht ändern müssen:
1 |
-(void)shouldAcceptTextChanges{ |
2 |
// If the isEditingItem flag is set to NO, then a new item has been
|
3 |
// added to the list. Otherwise an existing item has been edited.
|
4 |
if (!isEditingItem) { |
5 |
// Add the new item to the sampleDataArray.
|
6 |
[_sampleDataArray addObject:[_textInput getText]]; |
7 |
}
|
8 |
else{ |
9 |
// Replace the selected item into the array with the updated value.
|
10 |
NSUInteger index = [[_table indexPathForSelectedRow] row]; |
11 |
[_sampleDataArray replaceObjectAtIndex:index withObject:[_textInput getText]]; |
12 |
|
13 |
// Set the isEditingItem flag to NO.
|
14 |
isEditingItem = NO; |
15 |
}
|
16 |
|
17 |
// Reload the table using animation.
|
18 |
[_table reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic]; |
19 |
|
20 |
// Close the text input.
|
21 |
[_textInput closeTextInputView]; |
22 |
}
|
Denken Sie daran, dass beim Bearbeiten des Inhalts einer Zeile das entsprechende Objekt im Beispieldatenarray ersetzt wird. Achten Sie auch auf das isEditingItem. Es erhält wieder den NO-Wert.
Jetzt ist alles betriebsbereit. Führen Sie die App aus und testen Sie sie sowohl im Hoch- als auch im Querformat.
Abschluss
Wie Sie vielleicht bemerkt haben, lohnt es sich manchmal, benutzerdefinierte Ansichten zu erstellen, die Ihren Anforderungen besser entsprechen als die standardmäßigen iOS-SDK-Ansichten. Die benutzerdefinierte Text Input View ist eine wiederverwendbare Komponente mit geringen oder keinen Änderungen. Es kann in vielen Projekten verwendet werden, und wir haben alles mit einfachen Techniken und Programmierprinzipien gemacht. Diese benutzerdefinierte Text Input View, die jetzt allen zur Verfügung steht, kann ein Thema für weitere Anpassungen und Verbesserungen sein und wird hoffentlich für viele Programmierer nützlich sein! Im nächsten Tutorial werden wir dieses Projekt verwenden und eine neue Funktion hinzufügen, ein Accordion-Menü mit Optionen, die dem Benutzer zur Verfügung gestellt werden. Aber jetzt genießen Sie die benutzerdefinierte Text Input View!



