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

Программирование Android

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 5.00
CoolMind
419 / 402 / 65
Регистрация: 06.10.2012
Сообщений: 1,727
#1

PopupWindow. Что осталось за кадром? (Tutorial) - Программирование Android

27.08.2014, 17:46. Просмотров 1911. Ответов 7
Метки нет (Все метки)

Здравствуйте!
Недавно потребовалось сделать выпадающий список более вменяемым, чем это бывает у Spinner. Поискав, понял, что лучше всего в этом деле пригодится связка EditText + PopupWindow с ListView. Вариант с Dialog показался мне сложным или нереализуемым, поэтому выбор пал на PopupWindow.
Подпрограмма должна:
1) при нажатии на EditText открывать выпадающий список,
2) при нажатии на список сохранять выбранный элемент в EditText и закрывать список,
3) при нажатии вне списка закрывать список.
К сожалению, нормальных документов найти не смог и потому написал свою подпрограмму. Большинство авторов воспринимают PopupWindow как разновидность диалогового окна, в то время как там можно нарисовать не только надпись с кнопкой. Буду рад, если кому пригодится. Весь код пишу по памяти, он может не работать, но общую концепцию понять можно.
Итак, для начала научимся показывать всплывающее окно с какой-нибудь кнопкой (потом переделаем). Добавим файл с разметкой, назовём её popup_layout.xml:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Привет!"
        android:layout_gravity="center_horizontal" />
 
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Закрыть"
        android:layout_gravity="center_horizontal" />
</LinearLayout>
В форму, из которой будете вызывать PopupWindow, добавьте текстовое поле. Под ним будет появляться PopupWindow. Назовём его, например, txtCategory.
Java
1
2
3
4
5
6
7
8
9
private void showCategoriesWindow(LayoutInflater inflater) {
    /*Поскольку я открывал PopupWindow из Fragment, то инициализировать inflater не пришлось (передаём его из 
            onCreateView(final LayoutInflater inflater, ViewGroup viewGroup, Bundle SavedInstanceState)
    Если же вы вызываете PopupWindow из Activity, то инициализируем её так:
            LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);*/
    View popupView = inflater.inflate(R.layout.popup_layout, null);
    popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    popupWindow.showAsDropDown(txtCategory, 50, -20);
}
Далее запускаем:
Java
1
2
3
4
5
6
7
8
9
@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup viewGroup, Bundle SavedInstanceState) {
    View v = inflater.inflate(R.layout.fragment, viewGroup, false);
    ...
    EditText txtCategory = (EditText) v.findViewById(R.id.category);
    ...
    showCategoriesWindow(inflater);
    ...
}
Должно появиться окно с прозрачным фоном, находящееся недалеко от txtCategory (координаты можете заменить на свои). Закроем программу и напишем код для закрытия всплывающего окна.
Java
1
2
3
4
5
6
7
    Button btnClose = (Button) popupView.findViewById(R.id.button);
    btnClose.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            popupWindow.dismiss();
        }
    });
Теперь при нажатии кнопки PopupWindow будет исчезать. Если PopupWindow не закрыть, а затем закрыть приложение или перейти на другую форму, то приложение будет выдавать в LogCat ошибку. Большинство авторов про неё не упоминают.
Исправим сей недостаток:
Java
1
2
3
4
5
6
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (popupWindow != null)
            popupWindow.dismiss();
    }
Теперь попробуем улучшить разметку для PopupWindow. Сделаем не банальную кнопку, а список. Создайте разметку и назовите файл category_list.xml.
Например, так:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">
 
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Закрыть"
        android:layout_gravity="center_horizontal" />
 
    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
Добавим также описание каждого элемента списка. Будем сокращать не влезающие в экран строки (назовём файл category_list_item.xml):
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white" >
 
    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="17sp"
        android:ellipsize="end"
        android:singleLine="true"
        android:text="sample"
        android:gravity="center_vertical" />
 
</LinearLayout>
Свяжем PopupWindow со списком:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void showCategoriesWindow(LayoutInflater inflater) {
    View popupView = inflater.inflate(R.layout.category_list, null);
    popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    popupWindow.showAsDropDown(txtCategory, 0, 0);
 
    final ArrayList<String> arrList = new ArrayList<String>();
    // Заполните здесь arrList несколькими строчками.
    arrList.add("Россия");
    arrList.add("Беларусь");
    arrList.add("Украина");
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(
        getActivity().getApplicationContext(), R.layout.category_list_item, R.id.textView, arrList);
    final ListView listView = (ListView) popupView.findViewById(R.id.listView);
    listView.setAdapter(adapter);
 
    Button btnClose = (Button) popupView.findViewById(R.id.button);
    btnClose.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            popupWindow.dismiss();
        }
    });
}
Теперь при вызове showCategoriesWindow будет открываться окно с белым фоном, кнопкой и списком. Доработаем пример. Хочется, чтобы окно закрывалось при нажатии на элемент списка, а само значение попадало бы в текстовую надпись на форме.
Для этого вместо последних строк (закрытия окна по нажатию кнопки) напишем другие.
Java
1
2
3
4
5
6
7
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            txtCategory.setText(arrList.get(position));
            popupWindow.dismiss();
        }
    });
Теперь кнопку btnClose можно убрать из кода и разметки. Но если мы вызовем получившуюся процедуру, то увидим, что окно не закрывается. Оказывается (об этом тоже мало где написано), ListView не получает фокуса.
Исправим недочёт. Для этого можно, например, создание окна сделать с параметром true в конце:
Java
1
popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
Кстати, второй параметр при вызове этой процедуры - ширина окна, можете поменять её.
Кроме того, оказалось, что если пользователь нажимает пальцем за пределами PopupWindow, то ничего не происходит. А хотелось бы, чтобы список закрывался. Исправим процедуру.
Java
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
private void showCategoriesWindow(LayoutInflater inflater) {
    View popupView = inflater.inflate(R.layout.category_list, null);
    popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
    popupWindow.setBackgroundDrawable(new ColorDrawable());
    popupWindow.setOutsideTouchable(true);
    popupWindow.showAsDropDown(txtCategory, (int)(txtCategory.getWidth() * 0.1), 0);
 
    final ArrayList<String> arrList = new ArrayList<String>();
    arrCategoryId = new ArrayList<Integer>();
 
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(
        getActivity().getApplicationContext(), R.layout.category_list_item, R.id.textView, arrList);
    final ListView listView = (ListView) popupView.findViewById(R.id.listView);
    listView.setAdapter(adapter);
    arrList.add("Россия");
    arrList.add("Беларусь");
    arrList.add("Украина");
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            txtCategory.setText(arrList.get(position).trim());
            iCategory = arrCategoryId.get(position);
            popupWindow.dismiss();
        }
    });
}
Многие авторы в четвёртой строке пишут new BitmapDrawable(), но этот код устарел. Я пробовал посоветованный на stackoverflow вариант ShapeDrawable(), но у него есть один небольшой недостаток. Если ваше PopupWindow будет иметь, например, скруглённые углы, то в самых краях этих углов появятся чёрные точки. Поэтому я использовал ColorDrawable().
Осталось научить программму открывать и закрывать всплывающее окно по нажатию на текстовое поле.
Java
1
2
3
4
5
6
7
8
9
10
11
txtCategory.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (popupWindow == null) {
            showCategoriesWindow(inflater);
        }
        if (!popupWindow.isShowing()) {
            popupWindow.showAsDropDown(txtCategory, 0, 0);
        }
    }
});
2
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
27.08.2014, 17:46
Здравствуйте! Я подобрал для вас темы с ответами на вопрос PopupWindow. Что осталось за кадром? (Tutorial) (Программирование Android):

Button внутри PopupWindow - Программирование Android
Имеется PopupWindow, в котором размещен LinearLayout. В этот layout я добавляю TextView и Button. Все нормально отображается, однако при...

Не вызывается клавиатура внутри PopupWindow - Программирование Android
И снова здравствуйте! Все никак не могу побороть проблему с этим PopupView... Оказывается, внутри него не обрабатываются не только кнопки,...

Monitor, Semaphor, Mutex. что за кадром? - C#
Что при этом происходит в системе? (Как это реализовано?) Например, во что превращается код: Monitor.Enter(obj);

Выбрать, что коммутатор сделает с кадром - Cisco
Всем привет. Прилагаю скриншот вопроса. У меня здесь такой вариант, т.к. в таблице MAC адресов коммутатора нет MAC адреса хоста С, то...

Определить, что коммутатор сделает с полученным кадром - Cisco
Всем привет. Прилагаю скриншот вопроса. Как я понял, свитч уже знает адрес назначения, значит он перешлет кадр сразу на FA 0\6? Т.е. ответ...

Определить, что коммутатор сделает с полученным кадром 2 - Cisco
Всем привет. Прилагаю скриншот вопроса. Заранее спасибо за помощь!

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
CoolMind
419 / 402 / 65
Регистрация: 06.10.2012
Сообщений: 1,727
27.08.2014, 17:59  [ТС] #2
Длина сообщения ограничена, допишу сюда.
Цель создания PopupWindow состояла в том, чтобы улучшить выпадающий список (Spinner). Слишком длинные строки на экране смартфона должны быть усечены. Также планируется добавить функционал: при нажатии на элемент списка ниже должны появляться дочерние элементы, а уже потом пользователь выбирает нужный элемент. Пока работаю над этой задачей.
1
Spelcrawler
526 / 496 / 111
Регистрация: 12.03.2014
Сообщений: 1,649
Завершенные тесты: 1
27.08.2014, 18:24 #3
Эх ещеб скриншоты результата) Спасибо, интересно.
1
CoolMind
419 / 402 / 65
Регистрация: 06.10.2012
Сообщений: 1,727
28.08.2014, 19:18  [ТС] #4
Spelcrawler, спасибо за ваш интерес. Да, согласен, без снимков не то, завтра постараюсь добавить.

Добавлено через 22 часа 16 минут
Прикрепляю полученный снимок экрана. Пришлось стереть все данные из списка.
Единственная проблема данного решения - пока из-за того, что запретил пересоздание Activity, при повороте экрана ширина списка не меняется.
1
CoolMind
419 / 402 / 65
Регистрация: 06.10.2012
Сообщений: 1,727
28.08.2014, 19:21  [ТС] #5
Прикрепляю картинку...
3
Миниатюры
PopupWindow. Что осталось за кадром? (Tutorial)  
Nea14
1 / 1 / 0
Регистрация: 25.08.2015
Сообщений: 8
29.01.2017, 17:40 #6
Я понял так, что PopupWindow как отдельный класс не существует? Для фрагмента нужен класс, жизненный цикл и тд...Тут ничего такого нет, задаю только view, вся работа в вызываемой активности, правильно понял?
0
CoolMind
419 / 402 / 65
Регистрация: 06.10.2012
Сообщений: 1,727
31.01.2017, 11:09  [ТС] #7
Цитата Сообщение от Nea14 Посмотреть сообщение
Я понял так, что PopupWindow как отдельный класс не существует?
Пока что не устарел, всё на месте.
Цитата Сообщение от Nea14 Посмотреть сообщение
Для фрагмента нужен класс, жизненный цикл и тд...Тут ничего такого нет, задаю только view, вся работа в вызываемой активности, правильно понял?
Да, это обычный widget, т.е. по сути, view. Я тогда только начинал Андроид-программирование, поэтому статья несколько пафосна, может быть, сейчас бы сделал через Dialog или ещё как-то.
1
Nea14
1 / 1 / 0
Регистрация: 25.08.2015
Сообщений: 8
31.01.2017, 17:22 #8
Нормальная статья, теперь с материальным UI PopupWindow как-то не вяжется, я с ним правда еще толком и не разобрался, где бы найти полное описание. Popup окно мне не подошло: не раскрывается в нем Spinner. Взял slideUp и в него выдвигающимся сделал фрагмент, который и подменяю на разные view.
1
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
31.01.2017, 17:22
Привет! Вот еще темы с ответами:

Перевод Vulkan Tutorial и кое-что по GLSL - OpenGL
Можете найти тут: http://vulkanapi.ru/ А то автор там старается, переводит, а народу там мало.

Найти в матрице подматрицу такую, что бы сумма в подматрице была похожа на сумму всего что осталось - C (СИ)
В общем, в программе задается матрица с помощью двухмерного массива. Программа должна найти все варианты когда сумма в подматрице примерно...

Что делать вин 7 говорит что осталось 3 дня до заканчивания срока лицензии хотя ключ стоит отсчет начался относительно не давно... - Windows 7
Что делать вин 7 говорит что осталось 3 дня до заканчивания срока лицензии хотя ключ стоит отсчет начался относительно не давно жалко...

Работа с кадром - Matlab
Прошу о срочной помощи! Задание : подготовить кадр на котором будет изображение точечного источника, можно произвольного размера, к...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
31.01.2017, 17:22
Ответ Создать тему
Опции темы

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