📜 ⬆️ ⬇️

Taming the user interface on iPhone with MonoTouch.Dialog

monotouch The user interface is based on UITableView, a powerful table rendering widget that almost every application on the iPhone uses. UITableView is a powerful widget that can draw data in various ways, based on how you set up the widget itself.

Here is an example of all kinds of UITableView:

image
')
The content of UITableView is rendered by calling code written by a developer who provides data on demand. The protocol includes requests such as: “How many sections?”, “How many lines in section N?”, “What is the title of section N?” In the form of callbacks to provide the actual contents of the cell. Despite the power of the widget, creating a UI with it is quite problematic. Developers spend too much time repeating their actions, setting up each presentation, poor configuration, and the need to polish some of the settings. Porting many examples from Object-C to C #, I found the right option by repeating the same process over and over.

Calluses appeared on my fingers, but even at night I thought that I had found the wrong solution and there is an option for better. But at the time, I was doing simple line-by-line porting, I was not ready to create a new API on top of all this.

Recently, when my favorite Twitter client on the iPhone got my UI fucked up, I decided to write my own Twitter client. The first step was to create settings for my twitter account. As you understood, it is implemented through UITableView. I had to set up a model that responds to view events, switch'i and if'y were here and there, in general, no enjoyment of writing code. This is how MonoTouch.Dialog was born.

I wanted the class to be attached to the dialog box using reflection, something that would allow me to write a C # class and bind it to a UITableView:
class TwitterConfig {
[Section ( "Account" )]
[Entry] string Username;
[Password] string Password;

[Section ( "Settings" )]
bool AutoRefresh;
bool AutoLoad;
bool UseTwitterRetweet;
}


Instead of starting to use reflection, I created a view of the current dialog in memory. The idea was that the reflection would be a bridge that could use the engine code.

The engine code is built on the principle that each line can be a widget. It can contain text, a switch, a text field, a slider, a calendar, or any user-created control. I called it "Elements" and created the following:

MonoTouch.Dialog follows Apple HIG recommendations for the iPhone, giving you the opportunity to focus on the application as much as possible, and not on its details.

Also, UITableView is built on the basis of MVC, which allows you to effectively scale large data sets, most of the pages with settings and data do not require such complexity.

Another possibility is to solve all the problems with entering text: entering text, automatically moving to the next line when pressing Enter, aligning all the lines in the section, hiding the keyboard when reaching the end of the input.

API example in action:

image var root = new RootElement ( "Settings" ) {
new Section (){
new BooleanElement ( "Airplane Mode" , false ),
new RootElement ( "Notifications" , 0, 0) { Notifications }
new Section (){
new RootElement ( "Sound" ), { Sound },
new RootElement ( "Brightness" ){ Brightness },
new RootElement ( "Wallpaper" ){ Wallpaper }
},
new Section () {
new EntryElement ( "Login" , "Your login name" , "miguel" ),
new EntryElement ( "Password" , "Your password" , "password" , true ),
new DateElement ( "Select Date" , DateTime .Now),
new TimeElement ( "Select Time" , DateTime .Now),
}
}

By creating a RootElement, you can pass it to a DialogViewController to control:
var dv = new DialogViewController (root);
navigation.PushViewController (dv, true );

Reflection API


The Replication API checks the class for the presence of fields to which special attributes are attached.

An example of a class and how it is drawn:

image class AccountInfo {
[Section]
public bool AirplaneMode;

[Section ( "Data Entry" , "Your credentials" )]

[Entry ( "Enter your login name" )]
public string Login;

[Caption ( "Password" ), Password ( "Enter your password" )]
public string passwd;

[Section ( "Travel options" )]
public SeatPreference preference;
}

As you noticed, enumerators (SeatPreference) are automatically converted to radio, which UINavigationController uses to control, and the headers are taken from field names, this behavior can be customized using the [Caption] attribute.

Using attributes, you can specify the rendering methods, title, image, etc.

LINQ and MonoTouch.Dialog


Craig wrote a great conference application for Mix 2010. I helped him reduce the amount of code by removing all the duplicate code to set the UITableView for different parts of the application for MonoTouch.Dialog. Since the conference application works with the schedule in the database, I expanded MonoTouch.Dialog to improve work with LINQ.

In the same vein, as with System.Xml.Linq API, which allows you to create XML documents with nested LINQ definitions, you can use MonoTouch.Dialog to create a UI.

For the Craig application, I wrote a SessionElement that allows you to run sessions and show the title and location of the session.

The following code contains the UI from the “My Schedule” tab. Data is requested on demand (Apple recommends lazy loading for all views)
image public class FavoritesViewController : DialogViewController {
public FavoritesViewController () : base ( null ) { }

public override void ViewWillAppear ( bool animated)
{
var favs = AppDelegate.UserData.GetFavoriteCodes();
Root = new RootElement ( "Favorites" ) {
from s in AppDelegate.ConferenceData.Sessions
where favs.Contains(s.Code)
group s by s.Start into g
orderby g.Key
select new Section (MakeCaption ( "" , g.Key)) {
from hs in g
select (Element) new SessionElement (hs)
}
};
}
}

So use either of the two models that you prefer: Reflection for quick and easy work with the interface and data, or the Element API for more advanced customization of the user interface, without spending half your life writing a boilerplate code

I hope that all this has helped you guys spend more time improving their applications and less time writing routine code.

MonoTouch.Dialog is not perfect and does not contain all the wishes. I also welcome additions, you are not constrained by anything in this branch of the code and make any changes that seem to you to be necessary.

Source: https://habr.com/ru/post/85564/


All Articles