-
Добрый день,
Никак не могу разобраться, как без использования UINavigationController осуществить переход между формами.
Подскажите, пожалуйста, какова должна быть структура форм(ы) и кого с кем связать.
Ссылки на примеры приветствуются. -
-
Спасибо, Евгений. Я читал Вашу статью перед тем, как задал вопрос.
Дело в том, что используется лишь UIToolBar. UINavigationController и UINavigationBar нет.
Возможно, я чего-то не понимаю. Стоит задача: переключаться между формами по нажатии на кнопки ВНИЗУ экрана. Будьте добры, объясните, как реализовать данный функционал. -
Андрей
у меня несколько видов добавлены к главному контроллеру вида, а он в свою очередь точнее его view является подвидом окна.
Приблизительно так
[mainViewController.view addSubview:view1];
[mainViewController.view addSubview:view2];
[window addSubview: mainViewController.view];
(view1 и view2 могут быть видами других контроллеров, например вместо view1 можешь поставить ViewController1.view, в общем любой нужный тебе вид).
я решил проблему переключения между видами способом отключения видимости
изначально все временно ненужные виды делаю невидимыми
например подобной строкой.
[view1 setHidden:YES];
а потом при нажатии на кнопку можно спрятаному виду послать ту же комманду только с параметром "NO",
А вид который надо спрятать - та же комманда, параметр "YES"
Иными словами вид mainViewController.view постоянно на экране, но рисуется только один из его подвидов.
Но это только как вариант если необходимо быстро переключаться не уничтожая виды. Потому нужно следить за памятью, особенно если видов много и они перегружены всякими там картинками к примеру - программа может вылететь от нехватки памяти.
В таком случае лучшим вариантом будет освобождение вида, а когда он снова нужен - реинициализация, В данном случае появится больше тормозов при переключении, но реже будешь получать всякие MemoryWarning.
Так что выбор - либо память(стабильность работы программы), либо производительность.
Дополнительно посмотри в документации информацию по UIView.
особенно его методы в Managing the View Hierarchy
пара методов оттуда переключающие виды
– bringSubviewToFront:
– sendSubviewToBack: -
NYN'ja , мне, видимо сильно не хватает теоретических знаний в данной области. У меня не получилось воспроизвести то, что Вы описали.
Начнем с того, что я так и не понял, какова архитектура приложения:
1. используется один .xib файл или два или же это вообще не принципиально?
2. как выглядит иерархия контролов?
3. какие объекты связаны между собой.
Короче, споткнулся на ровном месте и буксую уже четвертый день.
Если б можно было опубликовать где-то исходники самого простого приложения, реализующего данную задачу, было бы здорово.
Заранее благодарен за помощь. -
1. У меня все виды и контролы в одном xib-файле.
2. Для каждого View у меня отдельный UIViewController(наследуемый).
В дальнейшем в методе applicationDidFinishLaunching делегата приложения(создается автоматом, при создании проекта) я организую саму иерархию контролов.
Чтобы какой-нибудь view отобразился на экране он должен стать подвидом главного окна приложения(свойство window в *DelegateApp). Также у каждого view(к window это тоже относится) может быть много subview.
Организовываю эти подвиды следующим образом:
у одного из контроллеров(UIViewController - назовем его MainViewController, разумеется он наследник от UIViewController) есть свойство view(как и у любого другого контроллера вида). Этот вид я добавляю как подвид к окну:
[window addSubview: mainViewController.view];
И до конца программы он у меня прицеплен к этому окну и, так сказать все время видим. Сам по себе этот вид пуст, ничего не отображает. К этому виду(не контроллеру, а виду) мы будем аналогично цеплять в качестве подвидов более значимые виды относящиеся к другим контроллерам.
[mainViewController.view addSubview:anotherViewController.view];
или, если у вида нет своего контроллера:
[mainViewController.view addSubview:view2];
таким образом на текущий момент организовано следующим образом
окно(window )
......./
главный_вид(mainViewController.view)
,,,,,,/......\
подвид1 подвид2(anotherViewController.view и view(наследует UIView))
после этого, вид который ты должен отобразить сразу после загрузки программы должен остаться вдидимым, а всем остальным видам посылаешь сообщение [view2 setHidden:YES] например.
Затем пользователь чтото нажал в этом виде и появилась необходимость переключиться в другой вид - выполняешь комманды:
[view2 setHidden:NO];//проявляешь нужный вид
[anotherViewController.view setHidden:YES];//прячешь старый вид(в памяти он висит)
Переключился.
Равно как и наоборот можно вернуться.
Это вполне рабочий пример из одной из моих программ.
Если непонятно как созданы виды и контроллеры - то лучше почитать статьи в блоге с начала, желательно все проработать, поищи описание создания класса из Интерфейс Билдера.
К слову подвиды можно добавлять напрямую к окну, особенно если программа не должна реагировать на изменение ориентации устройства. Я заметил что на повороты устройства отрабатывает только контроллер, вид которого первым добавлен к окну, потому все виды стараюсь добавлять к этому же контроллеру, даже если у них есть свои контроллеры.
3.если насчет связывания через оутлеты в билдере, то помочь вряд ли смогу, все зависит от конкретного проекта. А взаимосвязь в коде между видами я попытался обьяснить. Не знаю получилось ли, если нет, то могу разве что только рекомендовать обратиться к документации по UIView. И экспериментировать. Сам долго разбирался с этими видами. -
Всем привет!
Пытаюсь сделать нечто похожее, сейчас у меня на window цепляются два subview, у каждого свой вью контроллер, лежат они в двух разных xib-файлах.. ну и есть еще xib MainWindow - там Window и контроллеры. Проблема сейчас в том, как мне из метода, срабатывающего по нажатию на кнопку в одном из этих view, спрятать его и сделать видимым другой.. Вопрос мой из разряда "полный newbie", учиться программированию под iPhone начала меньше недели назад, так что очень буду благодарна за совет и помощь :)
Прячу текущий вью я так:
[self setHidden:YES];
а вот как показать второй - не знаю..
Пробовала так:
@interface SomeView : UIView {
//тут кучка переменных и IBOutlet'ов
vcOptions* vcOptions1; // vcOptions - view controller второй вьюшки
}
- (IBAction)ShowAnotherView;
@property (nonatomic, retain) IBOutlet vcOptions *vcOptions1;
@end
и
@implementation SomeView
//...
@synthesize vcOptions1;
//...
- (IBAction)OpenOptions {
[vcOptions1.view setHidden:NO];
[self setHidden:YES];
}
//...
@end
Понимаю, что это неправильный вариант, есть предположение, что надо как-то пробраться к делегату, ибо view к окну прикручивались в нем.. но не очень представляю как) -
- (IBAction)OpenOptions {
[vcOptions1.view setHidden:NO];
[self setHidden:YES];
}
тут имелось в виду:
- (IBAction)ShowAnotherView {
[vcOptions1.view setHidden:NO];
[self setHidden:YES];
} -
не забудьте подключить в классе вашей версии UIViewController-a класс делегата приложения
#import "MYAppDelegate.h"
а потом к делегату добраться легко:
MYAppDelegate *appDelegate =[[UIApplication sharedApplication] delegate];
После можно обращаться к окну и другим свойствам(например контроллерам и их видам) делегата
appDelegate.window (доступ к окну)
appDelegate.viewController1 (доступ к одному из контроллеров)
appDelegate.viewController1.view (доступ к виду контроллера)
Хотя не очень понял структуру видов в вашей программе.
Я так понимаю у вас есть window в делегате.
И есть виды(с контроллерами), подключенные к этому окну, или подключен к окну только один вид, а второй, по цепочке, является подвидом первого вида?
Я к тому что если вдруг они по цепочке друг ко другу подключены, то если superview(надвиду) послать сообщение сделаться невидимым, то все его подвиды тоже исчезнут, независимо от того что сами они "видимые". Переключение таким способом возможно только для видов на одном уровне вложености.
И опишите как отрабатывает ваш код:
-один вид исчезает, а второй не появляется
-вообще не реагирует на нажатие(не заходит в метод, проверяется брекпоинтом)
-В метод заходит но визуально команды абсолютно не выполняются
-выдает ошибки, компиляции
-выдает ошибки во время исполнения
-или свой вариант
Или проблема решилась через делегат -
Спасибо огромное! Проблема решилась через делегат.
Не хватало
MYAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
Раньше код отрабатывал как в первом варианте - один вид исчезал, а второй не появлялся, теперь всё работает как и было задумано, а виды находятся на одном уровне вложенности, оба подключены к окну.
Попутно возник вопрос на будущее - как реализовать вариант с освобождением вида и реинициализацией другого вида..
сейчас соответственно код метода:
myappDelegate *appDelegate =[[UIApplication sharedApplication] delegate];
[appDelegate.vcOptions1.view setHidden:NO];
[self setHidden:YES];
Правилен ли будет такой вариант?
myappDelegate *appDelegate =[[UIApplication sharedApplication] delegate];
[appDelegate.window addSubview:appDelegate.vcOptions1.view];
[appDelegate.vcGame1 release];
Попробовала запустить - переключения работают: 1->2->1->2->_TERMINATING_DUE_TO_UNCAUGTH_EXEPTION_
Удивило то, что первые несколько раз они все же отработали, и только потом словился эксепшн - причем ловится все время в одном и том же месте.. (кнопка на втором виде становится синей и приложение зависает, _nibName принимает значение invalid) -
Скорее всего свойство vcGame1 имело несколько retainCount(по-моему так пишется).
То есть на него было несколько ссылок. При сообщении release счетчик уменьшается на 1. И только тогда, когда он достигает 0 обьект удаляется. И в дальнейшем попытка обратиться к нему, вызовет ошибку, потому как его уже не существует.Часто если что-то отрабатывает несколько раз потом грохается - проблема скорее всего в ретайн\релиз.
Еще у любого view есть метод removeFromSuperview. Которым он сам себя убирает из его, скажем, родителя. При этом он не просто удаляет себя из массива подвидов, но еще и автоматом релизит себя. Если счетчик ссылок на него равнялся до этого единице, то после релиза он освобождает память. Потому лучше его не релизить, а исключать из подвидов. Необходимо исключить обращение к нему после освобождения(и не релизить его больше чем надо).
Насчет реинициализации - тоже самое что и инициализация нового обьекта через
[[MyViewClass alloc] init];
А затем после инициализации подключайте его к окну или к чему бы то ни было. -
Хотя отвечал раньше, но ответ почему-то ушел на премодерацию, и не был в результате отображен. Потому сейчас ответить так же подробно как в недошедшем посте не смогу.
Отвечу в общих чертах:
Вместо релиза вида нужно послать виду сообщение [view1 removeFromSuperview](в синтаксисе мог ошибиться, наизусть методы не помню).
Этот метод удаляет вид из массива подвидов его родителя, и автоматом должен саморелизится.
Если количество ссылок на вид было не больше 1, то вид после этого грохнется из памяти.
А то что несколько раз отработали переключения а потом грохнулись - это потому что у каждого обьекта есть счетчик ссылок на него, при достижении 0 обьект удаляется. А значит вы несколько раз можете освободить обьект - уменьшая количество ссылок на него, но когда обьект, после нескольких релизов - наконец-то удалится, то следующий релиз будет послан уже несуществующему обьекту, чем и вызвалась ошибка. Так я это понимаю.
Почитайте документацию на NSObject, а конкретно о свойствах и методах: retain, release, dealloc, retainCount, init. По моему все необходимые в этом плане места указал. -
Спасибо за ответы.
Необходимое решение было найдено тут: http://www.appsamuck.com/day2.html
По нажатию на кнопку i, показывается другой view. Убираем анимацию и наслаждаемся :)