- Русские Блоги
- Разница между атрибутами видимости VISIBLE, INVISIBLE и GONE в Android
- Интеллектуальная рекомендация
- Многослойная презентацияViewController Jap
- Распечатать список с конца до головы
- Типы данных и переменные
- Python Daily Practice (4) -идиомы заполняют музыку
- android recyclerview setVisibility View. GONE по-прежнему занимает место
- 4 ответа
- Android Architecture Components в связке с Data Binding
- Немного об MVVM
- Зачем нам это все надо?
- Описание примера
- Слой View
- Класс LiveData
- Слой Model
- Класс ViewModel
- Слой ViewModel
- Адаптация ViewModel под Data Binding
- Адаптация LiveData под Data Binding
- Не идеально, но получилось
Русские Блоги
Разница между атрибутами видимости VISIBLE, INVISIBLE и GONE в Android
В разработке для Android большинство элементов управления имеют атрибут видимости, а есть три атрибута: «видимый», «невидимый» и «пропавший». В основном используется для настройки отображения и скрытия элементов управления. Некоторые люди могут задаться вопросом, в чем разница между невидимым и ушедшим? ? ? Итак, с этим вопросом мы смотрим на следующее:
Это устанавливается следующим образом в файле XML и коде Java:
Видимый (видимый)
XML-файл: android: visibility = «visible»
Java-код: view.setVisibility (View.VISIBLE);
Невидимый (невидимый)
XML-файл: android: visibility = «invisible»
Java-код: view.setVisibility (View.INVISIBLE);
Спрятаться
XML-файл: android: visibility = «ушел»
Java-код: view.setVisibility (View.GONE);
Чтобы различить три, я построил Купол для демонстрации, сначала перейдем к кодексу Купола, после демонстрации я знаю разницу между ними:
- xml version = «1.0» encoding = «utf-8» ?>
- LinearLayout xmlns:android = «http://schemas.android.com/apk/res/android»
- android:layout_width = «fill_parent»
- android:layout_height = «fill_parent»
- android:orientation = «vertical» >
- LinearLayout
- android:layout_width = «fill_parent»
- android:layout_height = «wrap_content»
- android:orientation = «horizontal»
- android:layout_marginBottom = «20dip» >
- TextView
- android:layout_width = «wrap_content»
- android:layout_height = «wrap_content»
- android:layout_weight = «1»
- android:background = «#F00»
- android:text = «TextView1»
- android:textSize = «23sp»
- android:visibility = «visible»/>
- TextView
- android:id = «@+id/mainTV2»
- android:layout_width = «wrap_content»
- android:layout_height = «wrap_content»
- android:layout_weight = «1»
- android:background = «#00F»
- android:text = «TextView2»
- android:textSize = «23sp»
- android:visibility = «visible»/>
- LinearLayout >
- Button
- android:id = «@+id/mainBtn1»
- android:layout_width = «fill_parent»
- android:layout_height = «wrap_content»
- android:text = «TextView2 ВИДИМ»
- android:onClick = «mianOnClickListener»/>
- Button
- android:id = «@+id/mainBtn2»
- android:layout_width = «fill_parent»
- android:layout_height = «wrap_content»
- android:text = «TextView2 невидим»
- android:onClick = «mianOnClickListener»/>
- Button
- android:id = «@+id/mainBtn3»
- android:layout_width = «fill_parent»
- android:layout_height = «wrap_content»
- android:text = «TextView2 ушел»
- android:onClick = «mianOnClickListener»/>
- LinearLayout >
Пока последние три кнопки являются атрибутами, которые контролируют видимость TextView
- package com.chindroid.visibility;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.TextView;
- public class MainActivity extends Activity <
- /** TextView2 */
- private TextView mainTV2 = null ;
- @Override
- public void onCreate(Bundle savedInstanceState) <
- super .onCreate(savedInstanceState);
- setContentView(R.layout.main);
- // Инициализируем данные
- initData();
- >
- / ** Метод инициализации контроля * /
- private void initData() <
- mainTV2 = (TextView)findViewById(R.id.mainTV2);
- >
- /**
- Метод реагирования на событие нажатия кнопки в MainActivity
- *
- * @param v
- */
- public void mianOnClickListener(View v) <
- switch (v.getId()) <
- case R.id.mainBtn1: < // Событие ответа кнопки 1
- // Установить TextView2 как видимый
- mainTV2.setVisibility(View.VISIBLE);
- break ;
- >
- case R.id.mainBtn2: < // Событие ответа кнопки 2
- // Установить TextView2 как невидимый
- mainTV2.setVisibility(View.INVISIBLE);
- break ;
- >
- case R.id.mainBtn3: < // Ответное событие кнопки 3
- // Установить TextView2, чтобы скрыть
- mainTV2.setVisibility(View.GONE);
- break ;
- >
- default :
- break ;
- >
- >
- >
При запуске программы оба TextViews видны
Когда мы нажимаем первую кнопку и устанавливаем для свойства TextView2visibility значение INVISIBLE, процедура выглядит следующим образом:
Когда мы нажимаем третью кнопку и устанавливаем свойство TextView2visibility в GONE, процедура выглядит следующим образом:
Когда мы снова нажмем первую кнопку и установим свойство TextView2visibility в VISIBLE, TextView2 снова будет представлен, как показано на следующем рисунке:
VISIBLE: сделать элемент управления видимым
Невидимый: установите элемент управления невидимым
GONE: установить контроль, чтобы скрыть
Основное различие между INVISIBLE и GONE заключается в следующем: когда свойство видимости элемента управления равно INVISIBLE, интерфейс резервирует пространство, занимаемое элементом управления view, а когда свойство элемента управления равно GONE, интерфейс не сохраняет пространство, занимаемое элементом управления view.
Интеллектуальная рекомендация
Многослойная презентацияViewController Jap
. Недавно, проект использует многоэтажные прыжки [A presentViewController: B animated: YES] [B presentViewController: C animated: YES] . Проблема в том, где: как это идет прямо к? Я не нашел ме.
Распечатать список с конца до головы
В случае, когда таблица цепи не может изменять дисплей, данные хранения стека могут рассматриваться с рекурсивным методом. Разрешить модификацию структуры ссылки.
Типы данных и переменные
тип данных Компьютерная программа может обрабатывать различные значения. Однако компьютеры могут обрабатывать гораздо больше, чем числовые значения. Они также могут обрабатывать различные данные, таки.
Python Daily Practice (4) -идиомы заполняют музыку
оглавление 1. Одно место 2. Случайное расположение 3. Добавьте баллы для оценки 4. Получение файла 5. Установите уровень сложности. 6. Срок завершения 7. Выберите заполнение пропусков. 1. Одно место Н.
Источник
android recyclerview setVisibility View. GONE по-прежнему занимает место
Я хочу перечислить только не понравившиеся предметы в моем обзоре переработчика. У меня есть полный список элементов в rv в MainActivity (не устанавливал видимость здесь). Я могу установить для каждого элемента, как или не нравится, нажав на кнопку изображения. MainActivity отображает полный список элементов (просмотров карт), показывающих, нравится или нет кнопка изображения. Если элемент понравился, он сохраняется в базе данных Firebase как отдельная запись в разделе «Нравится» с ключом элемента (ключ Firebase .push), а не в разделе «Элементы». (в Firebase DB у меня есть пользователи, предметы, лайки).
Вот мой код подактивности, DislikedItemsActivity, где я хочу показать только те элементы, которые не нравятся с помощью setVisibility (View.GONE) для понравившихся элементов. Это по-прежнему содержит пространство между элементами для элементов View.GONE (хотя эти карты пустые).
Я искал много решений, таких как onBindViewHolder, notifyDataChanged, установить поле на 0, установить размер макета в xml на wrap_content. Лучшее, что я мог бы получить — это иметь ненужные элементы без пробела с помощью mRecyclerView.getAdapter (). NotifyItemRemoved (position) ;, но прокручивая список в обратном порядке, весь rv испорчен (дублирующаяся запись, пустые пробелы, неупорядоченный список).
Я не знаю, как перечислить только новые элементы из полного списка предметов из MainActivity rv в новом действии? Мой код выше показывает только не понравившиеся элементы, но только до тех пор, пока я не прокручиваю до конца списка, и если я прокручиваю назад, rv испортился. Я зарегистрировал позиции представлений (18 элементов) в onBindViewHolder, и сначала он считает все элементы в последовательности (17,16,15,14 . 0), но прокручивая от конца списка к обратному, позиция переходит от 0 до 4, как 7 раз (изменяется всегда, сколько раз), то же самое для элемента 5,6, до элемента 17 (все их позиции показывались в onBindViewHolder 7 или 8 раз во время прокрутки, т.е. 5,5,5,5,6,6,6 , 6) и только для обратной прокрутки и во время обратного перемещения rv показывает только не понравившиеся элементы или пустые представления или дублирующую запись не понравившегося элемента.
(не знаю, как добавить фото) Когда появляется неприязненный список, он показывает первый элемент (просмотр карты занимает весь экран), и когда я начинаю прокручивать список (от 1. видимого элемента до следующего видимого элемента), если есть пробел (item1 vis и next vis item 4), переставить, и я вижу, что следующий видимый элемент (item4) перемещается в 1. видимый элемент, затем остальная часть списка располагается хорошо, пока я не начну прокручивать назад, затем переставляет rv с пробелами и с двойным входом. Список движется взад и вперед до конца (длина всего списка предметов, а не только не понравившихся предметов), но все видимые предметы все перепутали.
4 ответа
Я нашел решение для фильтрации всей базы данных. В моем вопросе я хотел получить только понравившиеся / не понравившиеся элементы в отдельном упражнении, хотя мой предыдущий код показывал отфильтрованные элементы, но с пробелами. В приведенном ниже коде я изменил DatabaseReferences (mDatabase -node с полным списком элементов и mDatabaseItemsLiked -node с item uid и user uid).
Это дало только пустые карточки только с номером в качестве понравившихся элементов, но чтобы получить имя из базы данных mDatabase (полный список), я использовал dataSnapshot.getValue (Item.class) .getItemName ().
Это работает для меня без каких-либо проблем. Я надеюсь, что это эффективная сеть.
Используйте этот код для удаления занятого пространства:
Вы можете попытаться сохранить понравившийся элемент в boolean array , а затем в populateViewHolder проверить, есть ли у элемента значение «нет», и установить видимость.
Я бы сделал так:
- В вашем классе объявите:
this.itemLiked = new boolean [arrayOfAllItems.size]
itemLiked[position] = true; //Where position is row position
onBindViewholder или в вашем случае populateViewHolder:
if (! itemLiked [position]) <
viewHolder.mView.setVisibility ( View.GONE ) ; >
Надеюсь, это поможет, удачи!
EDITED Я не совсем понимаю, что вы хотите сделать, поэтому я оставляю вам код для двух случаев. Случай 1. Пометьте и размечайте строки. Случай 2. Сохранить в базе данных или удалить.
В продолжение полный код
XML-код операции add RecyclerView :
Создайте собственный макет для строки:
Сделайте Модельный класс:
Сделать класс адаптера:
И ваша деятельность:
Сохраняя выбранный элемент с помощью adaptorPosition в логических значениях, String, int . [], адаптер всегда узнает, что происходит с каждым элементом, и поэтому ваш список всегда будет упорядочен.
У меня тоже такая же проблема. я думал, что если RelativeLayout загрузить один за другим, высота = 0, спецификации будут удалены. Так что это работает для меня.
Это мой ViewHolder. Я представлю здесь свой отзывчивый план.
Я установил высоту и ширину
Источник
Android Architecture Components в связке с Data Binding
Не так давно для андроид-разработчиков Google представил новую библиотеку — Android Architecture Components. Она помогает реализовать в приложении архитектуру на основе паттернов MVx (MVP, MVVM etc.). Кроме того, уже давно выпущена другая библиотека от Google — Data Binding Library. Она позволяет прямо в разметке связывать отображение UI-контролов со значениями, содержащимися в объектах. Это важная особенность паттерна MVVM — связывать слой View со слоем ViewModel.
Обе библиотеки направлены на построение архитектуры Android-приложений в MVVM стиле.
Я расскажу, как можно использовать их вместе для создания проекта с архитектурой на основе MVVM.
Немного об MVVM
Паттерн MVVM предполагает разделение архитектуры приложения на 3 слоя:
- Model — слой данных. Содержит всю бизнес-логику приложения, доступ к файловой системе, базе данных, ресурсам системы и другим внешним сервисам;
- View — слой отображения. Все, что видит пользователь и с чем может взаимодействовать. Этот слой отображает то, что представлено в слое ViewModel. Также он отправляет команды (например, действия пользователя) на выполнение в слой ViewModel;
- ViewModel — слой представления. Связан со слоем View байндингами. Содержит данные, которые отображены на слое View. Связан со слоем Model и получает оттуда данные для отображения. Также обрабатывает команды, поступающие из слоя View, изменяя тем самым слой Model.
Основной интерес в статье будет прикован к байндингам. Это связи отображения конкретных параметров View (например, “text” у TextView) с конкретными полями представления ViewModel (например, поле “имя пользователя”). Задаются они в разметке View (в layout), а не в коде. ViewModel, в свою очередь, должна так представлять данные, чтобы их было легко связать байндингами с View.
Зачем нам это все надо?
Сам по себе паттерн MVVM, как и MVP, и MVC, позволяет разделить код на независимые слои. Основное отличие MVVM — в байндингах. То есть, в возможности прямо в разметке связать отображение того, что видно пользователю — слой View, с состоянием приложения — слоем Model. В общем, польза MVVM в том, чтобы не писать лишний код для связывания представления с отображением — за вас это делают байндинги.
Google двигается в сторону поддержки архитектуры на основе паттерна MVVM. Библиотеки Android Architecture Components (далее, AAC) и Data Binding — прямое тому подтверждение. В будущем, скорее всего, этот паттерн будет использоваться на большинстве проектах под Android.
На данный момент проблема в том, что ни AAC, ни Data Binding не предоставляет возможности реализовать MVVM паттерн в полной мере. AAC реализует слой ViewModel, но байндинги надо настраивать вручную в коде. Data Binding, в свою очередь, предоставляет возможность написать байндинги в разметке и привязать их к коду, но слой ViewModel надо реализовывать вручную, чтобы прокидывать обновление состояния приложения через байндинги к View.
В итоге, вроде бы, все уже готово, но разделено на две библиотеки, и чтобы это было действительно похоже на MVVM, нужно просто взять и объединить их.
В общем, что надо для этого сделать:
- реализовать слой View на байндингах;
- реализовать слой ViewModel на основе классов LiveData и ViewModel из AAC;
- связать эти два слоя минимальным количеством кода;
- оформить это так, чтобы это можно было переиспользовать в проектах.
Сделать это попробуем на примере простого экрана профиля пользователя.
Описание примера
На экране будет три элемента:
- кнопка войти/выйти. Текст зависит от того, авторизован пользователь или нет;
- поле ввода логина. Показывается, когда пользователь не авторизован;
- лэйбл с логином. Показывает логин авторизованного пользователя.
Логин будет храниться в SharedPreferences. Пользователь считается авторизованным, если в SharedPreferences записан какой-нибудь логин.
Для простоты не будут использоваться сторонние фреймворки, запросы к сети, а также отображение ошибок.
Слой View
Начну я со слоя View, чтобы было понятно, что будет видно пользователю на экране. Сразу же размечу нужные мне байндинги без привязки к конкретной ViewModel. Как это все будет работать — станет понятно позже.
Класс LiveData
Перед реализацией слоя Model надо разобраться с классом LiveData из AAC. Он нам понадобится для нотификации слоя ViewModel об изменениях слоя Model.
LiveData — это класс, объекты которого поставляют данные и их обновления подписчикам. Он представляет собой реализацию паттерна Observer. На LiveData можно подписаться, а сама LiveData реализует внутри то, как она будет вычислять и обновлять данные для подписчиков.
Особенность LiveData в том, что она может быть привязана к объекту жизненного цикла и активироваться, только когда такой объект в состоянии started. Это удобно для обновления слоя View: пока активити или фрагмент в состоянии started, это значит, что у них инициализирован весь UI и им нужны актуальные данные. LiveData реагирует на это и активизируется — рассчитывает актуальное значение и уведомляет подписчиков об обновлении данных.
Слой Model
От слоя Model нам нужна следующая функциональность: методы login(String login), logout() и возможность отслеживать текущий логин авторизованного пользователя на основе LiveData.
Добавим класс ProfileRepository, который будет отвечать за логику авторизации пользователя:
Этот объект разместим в Application, чтобы было проще получить к нему доступ, имея Context:
Класс ViewModel
Перед реализацией слоя ViewModel надо разобраться с основным классом из AAC, использующимся для этого.
ViewModel — это класс, представляющий объекты слоя ViewModel. Объект такого типа может быть создан из любой точки приложения. В этом классе всегда должен быть либо дефолтный конструктор (класс ViewModel), либо конструктор с параметром типа Application (класс AndroidViewModel).
Чтобы запросить ViewModel по типу, нужно вызвать:
ViewModel хранятся отдельно для каждой активити и для каждого фрагмента. При первом запросе они создаются и помещаются для хранения в активити или фрагменте. При повторном запросе — возвращается уже созданная ViewModel. Уникальность конкретной ViewModel — это ее тип или строковый ключ + где она хранится.
Создаются ViewModel и AndroidViewModel по умолчанию через рефлексию — вызывается соответствующий конструктор. Так что, при добавлении своих конструкторов, в методе ViewModelProviders.of(. ) нужно явно указывать фабрику создания таких объектов.
Слой ViewModel
От ProfileViewModel нам надо следующее:
- метод loginOrLogout, который будет представлять команду логина или логаута пользователя, в зависимости от того, авторизован ли пользователь;
- изменяемое значение isUserLoggedIn, которое будет представлять состояние — авторизован ли пользователь;
- изменяемое значение loggedInUser, которое будет представлять логин текущего авторизованного пользователя;
- изменяемое значение inputLogin, которое будет представлять то, что пользователь ввел на экране в поле логина.
Создадим ProfileViewModel и свяжем ее с ProfileRepository:
Теперь при вызове метода loginOrLogout в ProfileRepository будет обновляться LoginLiveData и эти обновления можно будет отображать на слое View, подписавшись на LiveData из ProfileViewModel.
Но LiveData и ViewModel пока что не адаптированы под байндинг, так что использовать этот код еще нельзя.
Адаптация ViewModel под Data Binding
С доступом к ViewModel из разметки проблем особых нет. Объявляем ее в разметке:
И устанавливаем в активити или фрагменте:
Адаптация LiveData под Data Binding
Адаптировать LiveData я решил на основе класса ObservableField. Он позволяет привязать изменяющееся значение произвольного типа к конкретному свойству view.
В моем примере надо будет прибайндить visibility у view к тому, авторизован пользователь или нет. А также свойство text к логину пользователя.
У ObservableField есть два метода — addOnPropertyChangedCallback и removeOnPropertyChangedCallback. Эти методы вызываются, когда добавляется и удаляется байндинг из view.
По сути, эти методы — те моменты, когда нужно подписываться и отписываться от LiveData:
Для подписки на LiveData я использовал метод observeForever. Он не передает объект жизненного цикла и активирует LiveData независимо от того, в каком состоянии находятся активити или фрагмент, на котором находятся view.
В принципе, из объекта OnPropertyChangedCallback можно достать view, из view — context, context привести к LifecycleActivity и привязать LiveData к этой активити. Тогда можно будет использовать метод observe(lifecycleObject, observer). Тогда LiveData будет активироваться только когда активити, на которой находится view, в состоянии started.
Выглядеть этот хак будет примерно так:
Теперь изменим ProfileViewModel так, чтобы к ней можно было легко прибайндиться:
Важно! В процессе тестирования обнаружился один неприятный недостаток в библиотеке Data Binding — прибайнденные view не вызывают метод removeOnPropertyChangedCallback даже когда активити умирает. Это приводит к тому, что слой Model держит ссылки на объекты слоя View через слой ViewModel. В общем, утечка памяти из объектов LiveDataField.
Чтобы этого избежать, можно использовать еще один хак и вручную обнулить все байндинги на onDestroy активити:
Кроме того, внимательные читатели могли заметить в разметке класс SafeEditText. В общем, он понадобился, из-за бага в Data Binding Library. Суть в том, что она добавляет в листенер вводимого текста через addTextChangedListener даже если этот листенер null.
Так как на этапе onDestroy я обнуляю модель, то сперва в EditText добавляется null-листенер, а потом обновляется текст, который стал тоже null. В итоге на onDestroy происходил NPE краш при попытке оповестить null-листенер о том, что текст стал null.
В общем, при использовании Data Binding будьте готовы к таким багам — их там довольно много.
Не идеально, но получилось
В общем, с некоторыми трудностями, хаками и некоторыми разочарованиями, но связать AAC и Data Binding получилось. Скорее всего, в скором времени (года 2?) Google добавит какие-нибудь фичи, чтобы связать их — тот же аналог моей LiveDataField. Пока что AAC в альфе, так что там многое еще может измениться.
Основные проблемы на текущий момент, на мой взгляд, связаны с библиотекой Data Binding — она не подстроена под работу с ViewModel и в ней есть неприятные баги. Это наглядно видно из хаков, которые пришлось использовать в статье.
Во-первых, при байндинге сложно получить активити или фрагмент, чтобы получить LifecycleObject, необходимый для LiveData. Эту проблему можно решить: либо достаем это через рефлексию, либо просто делаем observeForever, который будет держать подписку на LiveData, пока мы вручную не обнулим байндинги на onDestroy.
Во-вторых, Data Binding предполагает, что ObservableField и прочие Observable объекты живут тем же жизненным циклом, что и view. По факты эти объекты — это часть слоя ViewModel, у которой другой жизненный цикл. Например, в AAC этот слой переживает перевороты активити, а Data Binding, не обновляет байндинги после переворота активити — для нее все view умерли, а значит, и все Observable объекты тоже умерли и обновлять ничего нет смысла. Эту проблему можно решить обнулением байндингов вручную на onDestroy. Но это требует лишнего кода и необходимости следить, что все байндинги обнулены.
В-третьих, возникает проблема с объектами слоя View без явного жизненного цикла, например, ViewHolder адаптера для RecyclerView. У них нет четкого вызова onDestroy, так как они переиспользуются. В какой момент обнулять байндинги во ViewHolder — сложно сказать однозначно.
Не сказал бы, что на текущий момент связка этих библиотек выглядит хорошо, хотя использовать ее можно. Стоит ли использовать такой подход с учетом недостатков, описанных выше — решать вам.
Пример из статьи можно посмотреть на гитхабе Touch Instinct.
Источник