В основе пользовательского интерфейса лежит UITableView, мощный виджет по отрисовке таблиц, который использует, почти, каждое приложение на iPhone. UITableView — мощный виджет, которые умеет отрисовывать данные различными способами, основываясь на том, как вы настроили сам виджет.
Вот вам пример всевозможных видов UITableView:
Cодержимое UITableView рендерится вызовом кода, который пишет разработчик, который предоставляет данные по требованию. Протокол включает в себя такие запросы, как: «Сколько секций?», «Сколько строк в секции N?», «Какой заголовок секции N?» в виде колбэков для предоставления актуального содержимого ячейки. Не смотря на всю мощь виджета, создавать UI с его помощью довольно проблематично. Разработчики тратят слишком много времени, повторяя свои действия, настраивая каждое представление, скудная конфигурация и нужда в шлифовании некоторых настроек. Портируя многие примеры с Object-C на C# я находил нужный вариант повторяя один и тот же процесс снова и снова.
На моих пальцах появились мозоли, но даже по ночам я думал, что нашел не идеальное решение и существует вариант по лучше. Но в то время, я делал простое построчное портирование, я был не готов создать новое API поверх всего этого.
Недавно, когда мой любимый твиттер-клиент на iPhone испоганил свой UI, я решил написать свой собственный Twitter-клиент. Первым шагом было создать настройки для моего твиттер-аккаунта. Как вы поняли, это реализовывается через UITableView. Мне пришлось настроить модель, отвечающую на события представления, switch'и и if'ы были тут и там, вообщем никакого наслаждения от написания кода. Вот так и родился MonoTouch.Dialog.
Я хотел, чтобы с помощью рефлекции класс мог привязаться к диалоговому окну, что-то, что позволило бы мне написать C# класс и привязать его к UITableView:
Вместо того, чтобы начать использовать рефлекцию, я создал представление текущего диалога в памяти. Идея была в том, что рефлекция будет мостом, который может использовать код движка.
Код движка построен по принципу — каждая строка может быть виджетом. Она может содеражить текст, переключатель, текстовое поле, слайдер, календарь или любой созданный пользователем элемент управления. Я назвал это «Elements» и создал следующие:
MonoTouch.Dialog следует рекомендациям Apple HIG для iPhone, давая возможность максимально сфокусироваться на приложении, а не на его мелочах.
Также, UITableView построен на основе MVC, которая позволяет эффективно масштабировать большие наборы данных, большинство страниц с настройками и данными не требуют такой сложности.
Другой возможностью является, решение всех проблем с вводом текста: ввод текста, автоматический переход на следующую строку при нажатии Enter, выравнивание всех линий в секции, скрытие клавиатуры при достижении конца ввода.
Пример API в действии:
Создав RootElement, вы можете передавать его в DialogViewController для управления:
API реплекции проверяет класс на наличие полей, к которым привязаны специальные атрибуты.
Пример класса и как он отрисовывается:
Как вы заметили, энумераторы(SeatPreference) автоматически преобразуются в radio, которое использует UINavigationController для управления, а заголовки берутся из имен полей, данное поведение можно настроить с помощью атрибута [Caption].
С помощью атрибутов, можно задать способы отрисовывания, заголовок, изображение и т.д.
Крэйг написал отличное приложение для конференции для Mix 2010. Я помог ему уменьшить количество кода, удалив весь повторяющийся код, чтобы установить UITableView для различных частей приложения для MonoTouch.Dialog. Так как приложение конференции работает с расписанием в базе данных, я расширил MonoTouch.Dialog для улучшения работы с LINQ.
В том же духе, как и с System.Xml.Linq API, который позволяет вам создавать XML документы с вложенными LINQ-определениями, вы можете использовать MonoTouch.Dialog для создания UI.
Для приложения Крэйга, я написал SessionElement, который позволяет запустить сессии и показывать заголовок и местоположение сессии.
Следующий код содержит UI с закладки «My Schedule». Данные запрашиваются по требованию (Apple рекомендует «ленивую» загрузку для всех представлений)
Так что используйте любую из двух моделей, которая вам больше нравится: Reflection для быстрой и простой работы с интерфейсом и данными или Element API для более продвинутой настройки пользовательского интерфейса, не тратя полжизни на написание boilerplate кода
Я надеюсь, что все это помогло вам, ребята, потратить больше времени на улучшения своих приложений и меньше времени на написания рутинного кода.
MonoTouch.Dialog не идеален и не содержит всех пожеланий. Также я приветствую дополнения, вы не скованы ничем в данной ветке кода и вносите любые изменения, которые покажутся вам нужными.
Вот вам пример всевозможных видов UITableView:
Cодержимое UITableView рендерится вызовом кода, который пишет разработчик, который предоставляет данные по требованию. Протокол включает в себя такие запросы, как: «Сколько секций?», «Сколько строк в секции N?», «Какой заголовок секции N?» в виде колбэков для предоставления актуального содержимого ячейки. Не смотря на всю мощь виджета, создавать UI с его помощью довольно проблематично. Разработчики тратят слишком много времени, повторяя свои действия, настраивая каждое представление, скудная конфигурация и нужда в шлифовании некоторых настроек. Портируя многие примеры с Object-C на C# я находил нужный вариант повторяя один и тот же процесс снова и снова.
На моих пальцах появились мозоли, но даже по ночам я думал, что нашел не идеальное решение и существует вариант по лучше. Но в то время, я делал простое построчное портирование, я был не готов создать новое API поверх всего этого.
Недавно, когда мой любимый твиттер-клиент на iPhone испоганил свой UI, я решил написать свой собственный Twitter-клиент. Первым шагом было создать настройки для моего твиттер-аккаунта. Как вы поняли, это реализовывается через UITableView. Мне пришлось настроить модель, отвечающую на события представления, switch'и и if'ы были тут и там, вообщем никакого наслаждения от написания кода. Вот так и родился MonoTouch.Dialog.
Я хотел, чтобы с помощью рефлекции класс мог привязаться к диалоговому окну, что-то, что позволило бы мне написать C# класс и привязать его к UITableView:
class TwitterConfig {
[Section ("Account")]
[Entry] string Username;
[Password] string Password;
[Section ("Settings")]
bool AutoRefresh;
bool AutoLoad;
bool UseTwitterRetweet;
}
Вместо того, чтобы начать использовать рефлекцию, я создал представление текущего диалога в памяти. Идея была в том, что рефлекция будет мостом, который может использовать код движка.
Код движка построен по принципу — каждая строка может быть виджетом. Она может содеражить текст, переключатель, текстовое поле, слайдер, календарь или любой созданный пользователем элемент управления. Я назвал это «Elements» и создал следующие:
- BooleanElement — отрисовка с помощью UISwitch
- FloatElement — слайдер
- HtmlElement — при нажатии запускает веб-браузер
- StringElement — отображает простой текст
- MultilineElement — многострочный текст
- RadioElement — единичный выбор со списка
- CheckboxElement — как BooleanElement, но вместо UISwitch использует checkbox
- ImageElement — позволяет пользователю выбрать картинку или сделать фотографию
- EntryElement — текстовое поле
- DateTimeElement, DateElement, TimeElement — выбор даты/дат и времени
MonoTouch.Dialog следует рекомендациям Apple HIG для iPhone, давая возможность максимально сфокусироваться на приложении, а не на его мелочах.
Также, UITableView построен на основе MVC, которая позволяет эффективно масштабировать большие наборы данных, большинство страниц с настройками и данными не требуют такой сложности.
Другой возможностью является, решение всех проблем с вводом текста: ввод текста, автоматический переход на следующую строку при нажатии Enter, выравнивание всех линий в секции, скрытие клавиатуры при достижении конца ввода.
Пример API в действии:
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),
}
}
Создав RootElement, вы можете передавать его в DialogViewController для управления:
var dv = new DialogViewController (root);
navigation.PushViewController (dv, true);
Reflection API
API реплекции проверяет класс на наличие полей, к которым привязаны специальные атрибуты.
Пример класса и как он отрисовывается:
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;
}
Как вы заметили, энумераторы(SeatPreference) автоматически преобразуются в radio, которое использует UINavigationController для управления, а заголовки берутся из имен полей, данное поведение можно настроить с помощью атрибута [Caption].
С помощью атрибутов, можно задать способы отрисовывания, заголовок, изображение и т.д.
LINQ и MonoTouch.Dialog
Крэйг написал отличное приложение для конференции для Mix 2010. Я помог ему уменьшить количество кода, удалив весь повторяющийся код, чтобы установить UITableView для различных частей приложения для MonoTouch.Dialog. Так как приложение конференции работает с расписанием в базе данных, я расширил MonoTouch.Dialog для улучшения работы с LINQ.
В том же духе, как и с System.Xml.Linq API, который позволяет вам создавать XML документы с вложенными LINQ-определениями, вы можете использовать MonoTouch.Dialog для создания UI.
Для приложения Крэйга, я написал SessionElement, который позволяет запустить сессии и показывать заголовок и местоположение сессии.
Следующий код содержит UI с закладки «My Schedule». Данные запрашиваются по требованию (Apple рекомендует «ленивую» загрузку для всех представлений)
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)
}
};
}
}
Так что используйте любую из двух моделей, которая вам больше нравится: Reflection для быстрой и простой работы с интерфейсом и данными или Element API для более продвинутой настройки пользовательского интерфейса, не тратя полжизни на написание boilerplate кода
Я надеюсь, что все это помогло вам, ребята, потратить больше времени на улучшения своих приложений и меньше времени на написания рутинного кода.
MonoTouch.Dialog не идеален и не содержит всех пожеланий. Также я приветствую дополнения, вы не скованы ничем в данной ветке кода и вносите любые изменения, которые покажутся вам нужными.