Форум программистов, компьютерный форум, киберфорум
Наши страницы

Программирование iOS/iPhone

Войти
Регистрация
Восстановить пароль
 
VV0lk
11 / 1 / 0
Регистрация: 25.12.2011
Сообщений: 174
#1

Правильная обработка нажатя кнопки в TableView - Программирование iOS

14.02.2015, 19:30. Просмотров 1456. Ответов 6
Метки нет (Все метки)

Здравствуйте. Пишу на Mono. Заполнил таблицу кастомными ячейками, состоящими из кнопки и лейбла и огбычными. При нажатии на кнопку в ячейке соответствующая ячейка должна удалиться. Вот код:
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
        {
            _tableView = tableView;
 
            var cur_lang =  _User_Data.cur_lang;
 
            if (TextLabelList.Count > 0)
                TextLabelList.RemoveRange (0, TextLabelList.Count);
 
            TextLabelList.Add (cur_lang._add_str);
            TextLabelList.Add (cur_lang._del_all);
 
            foreach (string str in _User_Data.name_mash_picker_list)
                TextLabelList.Add (str);
 
 
            //первые две и после основного списка ячейки идут с кнопкой
            if ((indexPath.Row < 2) || (indexPath.Row >= _User_Data.name_mash_picker_list_start_Count+2)) 
            {
                //"CellID_But"
                var cell = tableView.DequeueReusableCell ("CellID_But") as customViewCell_with_Button;
 
                if (cell == null)
                    cell = new customViewCell_with_Button ();
                    
 
                if (cell.cell_button.Tag == 0) {
                    cell.cell_button.Tag = indexPath.Row;
                    cell.cell_button.TouchUpInside += Touch_Delbtn_on_cell;
                }
                            
                cell.cell_Label.Text = TextLabelList [indexPath.Row];
 
                return cell;
            } 
            else
            {
                //далее обычные ячейки
                UITableViewCell cell = tableView.DequeueReusableCell ("cellIdentifier");
                // if there are no cells to reuse, create a new one
                if (cell == null)
                    cell = new UITableViewCell (UITableViewCellStyle.Default, "cellIdentifier");
                cell.TextLabel.Text = TextLabelList [indexPath.Row];;
                return cell;
            }
 
 
        }
 
 
               void Touch_Delbtn_on_cell(object sender, EventArgs e) //обработчик нажатия кнопки удалить
        {
            var but = (UIButton)sender;
            _User_Data.name_mash_picker_list.RemoveAt (but.Tag-2); //удалить элемент соответствующий кнопке
 
            _tableView.ReloadData ();
            System.IO.File.Delete (dbPath); //удалить файл
            BinaryWriter bw = new BinaryWriter(new FileStream(dbPath, FileMode.OpenOrCreate));
            for(int i=_User_Data.name_mash_picker_list_start_Count; i<_User_Data.name_mash_picker_list.Count; i++)  //переписать текущий список в файл
                bw.Write(Convert.ToDouble(_User_Data.name_mash_picker_list[i]));
            bw.Close(); 
 
        }

Но так как GetCell вызывается каждый раз при появлении ячейки на экране (например вышла из поля невидимости при скролле), то и обработчик события нажатия добавляется несколько раз и соответственно вызывается потом при нажатии тоже несколько раз. Что приводит к удалению не только своей но и соседних ячеек, так как те уже успели поменять свой индекс в списке. Никакой проверки на то, был ли уже добавлен объекту обработчик событий или нет, я не знаю.. Подскажите как быть в такой ситуации? Подобный вопрос я нашел на ксамариновском форуме, но решения я там что то не увидел: https://forums.xamarin.com/discussio...itableviewcell У меня есть конечно одна идея на этот счёт, но я ещё не проверял, насколько она рабочая. В общем кнопку на ячейке сделать объектом дочернего класса, наследованного от UIButton в котором лишь добавить свойство String_Tag, в которое при добавлении ячейки писалось бы то же самое что и на лейбле. А в обработчике нажатия искать элемент в списке с таким текстом и удалять. Таким образом заходить в обработчик может сколько угодно раз, но удалять только один, в остальных случаях он просто не найдет этот элемент в списке. Но это - костыль, а как правильно? Подскажите.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.02.2015, 19:30
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Правильная обработка нажатя кнопки в TableView (Программирование iOS):

Связанные TableView - Swift
Подскажите как мне реализовать два связанных TableView на одном ViewController? Мне не понятны следующие моменты: 1) Как в одном...

Как удалить элемент из TableView - Swift
Здравствуйте! В обычной ситуации для отображения кнопки удаления слайдом в TableView достаточно сделать следующее: class...

Запись данных в ячейку TableView - Программирование iOS
Добрый день. Я только начинаю программировать под iOS, сейчас изучаю работу с таблицами и столкнулся с такой проблемой: пробую добавить в...

Не раскрывается (исчез) TableView на ScrollView - Программирование iOS
Здравствуйте. Есть TableView, на обычной вьюхе всё работает нормально. Высота ячеек рассчитывается и т.д. Но вот когда я сделал вью...

Передать значение в TableView с сайта - Swift
Приветствую! Подскажите пожалуйста, каким способом лучше передавать в ячейки компонента данные с сайта? Я сейчас изучаю JSON, но...

Swipe в tableview iOS9 xcode7 - Swift
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int { return self.sotr.count } ...

6
Vorona
Peace 2 all shining faces
671 / 533 / 45
Регистрация: 05.03.2010
Сообщений: 1,283
15.02.2015, 16:41 #2
ну во-первых вы создаете ячейку следующим образом:
сначала пытаетесь получить ячейку по reuseIdentifier, если ее нет, тогда уже создаете ее, подписываетесь на все события и все
у вас не получится подписаться на ее события дважды таким образом

потом оперируйте больше датасорсом, а не самими ячейками, т.е. есть массив данных, и когда нажимаете удалить, тогда удаляете данные из массива и перерисовываете табличку, все.
никаких привязок к ui, особенно, который динамически строится и меняется, только датасорс, только хардкор

p.s. не знаю, правда, как в xamarin все это сделано, но знаю что они полностью копируют нативный api, потому мы можем общаться на языке этих терминов
0
VV0lk
11 / 1 / 0
Регистрация: 25.12.2011
Сообщений: 174
15.02.2015, 20:41  [ТС] #3
ну во-первых вы создаете ячейку следующим образом:
сначала пытаетесь получить ячейку по reuseIdentifier, если ее нет, тогда уже создаете ее, подписываетесь на все события и все
у вас не получится подписаться на ее события дважды таким образом
Ну я так и делаю вроде.
C#
1
2
3
4
 var cell = tableView.DequeueReusableCell ("CellID_But") as customViewCell_with_Button;
 
                if (cell == null)
                    cell = new customViewCell_with_Button ();
Но cell никогда не бывает равно нулю. Поэтому обработчик события добавляется каждый раз при заходе в GetCell и соответственно по наступлении события он зайдет в обработчик столько раз, сколько было добавлено.
потом оперируйте больше датасорсом, а не самими ячейками, т.е. есть массив данных, и когда нажимаете удалить, тогда удаляете данные из массива и перерисовываете табличку, все.
никаких привязок к ui, особенно, который динамически строится и меняется, только датасорс, только хардкор
Я так и делаю.
C#
1
2
_User_Data.name_mash_picker_list.RemoveAt (but.Tag-2); //удалить элемент списка соответствующий кнопке
            _tableView.ReloadData ();// перерисовать таблицу
Где name_mash_picker_list это список (List<string>) строк. Это и есть датасорс. Никаких ячеек я не удаляю. Тут дело в том, что например я нажал кнопку с тегом 5 (кнопку в пятой строке) соответственно удалиться элемент списка с индексом 5 (на but.Tag-2 не обращайте внимания. так надо. ) таблица перестроилась и теперь в списке элементов под пятым номером уже другой элемент, но тут в обработчик программа заходит ещё раз, так как обработчик события добавлялся столько раз, сколько отрисовывалась конкретная ячейка. И удаляет опять элемент с номером 5, а там уже находится совсем другой элемент, который мы не хотим удалять. Т.о. при нажатии на кнопку удалить может удалиться только та ячейка которая нужна, а может и вместе с несколькими соседними.
0
Vorona
Peace 2 all shining faces
671 / 533 / 45
Регистрация: 05.03.2010
Сообщений: 1,283
16.02.2015, 02:21 #4
Цитата Сообщение от VV0lk Посмотреть сообщение
Но cell никогда не бывает равно нулю.
cell будет равна null столько раз, сколько ее нужно будет создать снуля, так как она еще не была помещена в очередь для переиспользования

Цитата Сообщение от Vorona Посмотреть сообщение
сначала пытаетесь получить ячейку по reuseIdentifier, если ее нет, тогда уже создаете ее, подписываетесь на все события
убирая все условия с тегом, я это имел ввиду
C#
1
2
3
4
5
var cell = tableView.DequeueReusableCell ("CellID_But") as customViewCell_with_Button;
if (cell == null) {
    cell = new customViewCell_with_Button ();
    cell.cell_button.TouchUpInside += Touch_Delbtn_on_cell;
}
0
VV0lk
11 / 1 / 0
Регистрация: 25.12.2011
Сообщений: 174
16.02.2015, 09:07  [ТС] #5
убирая все условия с тегом, я это имел ввиду
Код C#
var cell = tableView.DequeueReusableCell ("CellID_But") as customViewCell_with_Button;
if (cell == null) {
cell = new customViewCell_with_Button ();
cell.cell_button.TouchUpInside += Touch_Delbtn_on_cell;
}
Так я уже пробовал. И сейчас попробовал ещё раз. Ставлю брекпоинт после if (cell == null) и программа туда не заходит ни разу! А таблица нормально строится. Почему так, понять не могу!

Добавлено через 2 минуты
Вот мой класс кастомной ячейки:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.CodeDom.Compiler;
 
namespace Storyboard.Manual
{
    partial class customViewCell_with_Button : UITableViewCell
    {
        public static readonly NSString Key = new NSString("CustomViewCell_with_Button");
 
 
    
        public UILabel cell_Label{
            get {
                return Cell_Label;
            }
        }
 
        public UIButton cell_button{
            get {
                return Cell_Button;
            }
        }
            
        public customViewCell_with_Button() : base()
        {
 
        }
 
        public customViewCell_with_Button (IntPtr handle) : base (handle)
        {
        }
 
    }
}
0
Melzas
38 / 38 / 4
Регистрация: 20.07.2011
Сообщений: 88
16.02.2015, 16:07 #6
Цитата Сообщение от VV0lk Посмотреть сообщение
Ставлю брекпоинт после if (cell == null) и программа туда не заходит ни разу!
Метод dequeueReusableCell (начиная с какого-то обновления iOS) сам создает ячейку при необходимости (хотя кажется это работает только если табличка в сториборде, для нибов все по старому).

Цитата Сообщение от VV0lk Посмотреть сообщение
обработчик события нажатия добавляется несколько раз и соответственно вызывается потом при нажатии тоже несколько раз
Можно удалить все предыдущие обработчики перед добавлением нового. Можно передавать в кастомную ячейку блок, который будет вызываться при нажатии кнопки (или что там в C# вместо блоков? Лямбды?).
0
VV0lk
11 / 1 / 0
Регистрация: 25.12.2011
Сообщений: 174
16.02.2015, 16:18  [ТС] #7
Метод dequeueReusableCell (начиная с какого-то обновления iOS) сам создает ячейку при необходимости (хотя кажется это работает только если табличка в сториборде, для нибов все по старому).
Я как раз со сторибордом и работаю.
Можно удалить все предыдущие обработчики перед добавлением нового.
Можно, но не известно сколько их было добавлено до этого, чтобы знать сколько удалять.
Можно передавать в кастомную ячейку блок, который будет вызываться при нажатии кнопки (или что там в C# вместо блоков? Лямбды?).
Не до конца понял что вы имеете в виду.
В общем сегодня сделал так, как задумывал на выходные. И все заработало. Переопределил класс кнопки кастомной ячейки дочерним классом от UIButton, добавив в него строковое свойство Tag_String.
И в GetCell написал такой вот код:
C#
1
2
3
4
5
6
cell.cell_button.Tag = indexPath.Row;
if(cell.cell_button.Tag_String==null)
        cell.cell_button.TouchUpInside += Touch_Delbtn_on_cell;
cell.cell_button.Tag_String=TextLabelList[indexPath.Row];
cell.cell_button.SetBackgroundImage(image, UIControlState.Normal);
cell.cell_Label.Text = TextLabelList [indexPath.Row];
А в обработчике нажатия вот такой:
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    void Touch_Delbtn_on_cell(object sender, EventArgs e)
        {
            var button = (UIMyButton_on_cell)sender;
 
            if (button.Tag == 0) {
                Add_new_element (_tableView);
                return;
            }
            if (button.Tag == 1) {
                Del_all_element (_tableView);
                return;
            }
 
            var findindex = _User_Data.name_mash_picker_list.FindIndex(x => x.Equals(button.Tag_String)); //найти элемент в списке с такой строкой.
            
        
            if(findindex>1)
                _User_Data.name_mash_picker_list.RemoveAt (findindex);//удалить этот элемент
                
            _tableView.ReloadData ();
            System.IO.File.Delete (dbPath); //удалить  файл-список
            BinaryWriter bw = new BinaryWriter(new FileStream(dbPath, FileMode.OpenOrCreate));
            for(int i=_User_Data.name_mash_picker_list_start_Count; i<_User_Data.name_mash_picker_list.Count; i++)  //переписать текущий список в файл
                bw.Write(Convert.ToDouble(_User_Data.name_mash_picker_list[i]));
            bw.Close(); 
 
        }

Теперь в обработчик заходит только один раз и делает все что мне надо. Всем спасибо!
0
16.02.2015, 16:18
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.02.2015, 16:18
Привет! Вот еще темы с ответами:

TableView - изменение анимации удаления ячеек - Программирование iOS
Всем привет! Есть такая ситуация: Заказчик приложения возмущен новой анимацией удаления ячеек в iOS7 и хочет, &quot;чтобы было, как...

Загрузка картинок в ячейках TableView - Objective-C
Всем привет! Метод LoadingImage вызывается при создании ячейки tableview, а в методе connectionDidFinishLoading данные еще не загружены...

QML TableView. Обработка данных - C++ Qt - C++ Qt
Всем доброго времени суток. У меня есть QML TableView, я выбираю из под c++ в QFileDialog файлы, и мне нужно передать данные о них в...

Правильная обработка ошибок - Visual Basic
Здравствуйте. У меня такой вопрос. Программа сама записывает файл по сети. Если сеть выключенна то на том компьюторре на котором работает,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru