Что содержит файл layout xml
Как правило, для определения визуального интерфейса в проектах под Android используются специальные файлы xml. Эти файлы являются ресурсами разметки и хранят определение визуального интерфейса в виде кода XML. Подобный подход напоминает создание веб-сайтов, когда интерфейс определяется в файлах html, а логика приложения - в коде javascript.
Объявление пользовательского интерфейса в файлах XML позволяет отделить интерфейс приложения от кода. Что означает, что мы можем изменять определение интерфейса без изменения кода java. Например, в приложении могут быть определены разметки в файлах XML для различных ориентаций монитора, различных размеров устройств, различных языков и т.д. Кроме того, объявление разметки в XML позволяет легче визуализировать структуру интерфейса и облегчает отладку.
Файлы разметки графического интерфейса располагаются в проекте в каталоге res/layout . По умолчанию при создании проекта с пустой activity уже есть один файл ресурсов разметки activity_main.xml , который может выглядеть примерно так:
В файле определяются все графические элементы и их атрибуты, которые составляют интерфейс. При создании разметки в XML следует соблюдать некоторые правила: каждый файл разметки должен содержать один корневой элемент, который должен представлять объект View или ViewGroup .
В данном случае корневым элементом является элемент ConstraintLayout , который содержит элемент TextView .
Как правило, корневой элемент содержит определение используемых пространств имен XML. Например, в коде по умолчанию в ConstraintLayout мы можем увидеть такие атрибуты:
Каждое пространство имен задается следующим образом: xmlns:префикс="название_ресурса" . Например, в
Название ресурса (или URI - Uniform Resource Indicator) - "http://schemas.android.com/apk/res/android" . И этот ресурс сопоставляется с префиксом android ( xmlns:android ). То есть через префикс мы сможем ссылаться на функциональность этого пространства имен.
Каждое пространство имен определяет некоторую функциональность, которая используется в приложении, например, предоставляют теги и атрибуты, которые необходимые для построения приложения.
xmlns:android="http://schemas.android.com/apk/res/android" : содержит основные атрибуты, которые предоставляются платформой Android, применяются в элементах управления и определяют их визуальные свойства (например, размер, позиционирование). Например, в коде ConstraintLayout используется следующий атрибут из пространства имен "http://schemas.android.com/apk/res/android":
xmlns:app="http://schemas.android.com/apk/res-auto" : содержит атрибуты, которые определены в рамках приложения. Например, в коде TextView:
xmlns:tools="http://schemas.android.com/tools" : применяется для работы с режиме дизайнера в Android Studio
Это наиболее распространенные пространства имен. И обычно каждый корневой элемент (не обязательно только ConstraintLayout) их содержит. Однако, если вы не планируете пользоваться графическим дизайнером в Android Studio и хотите работать целиком в коде xml, то соответственно смысла в пространстве имен "http://schemas.android.com/tools" нет, и его можно убрать.
При компиляции каждый XML-файл разметки компилируется в ресурс View. Загрузка ресурса разметки осуществляется в методе Activity.onCreate. Чтобы установить разметку для текущего объекта activity, надо в метод setContentView() в качестве параметра передать ссылку на ресурс разметки.
Для получения ссылки на ресурс в коде java необходимо использовать выражение R.layout.[название_ресурса] . Название ресурса layout будет совпадать с именем файла, поэтому чтобы использовать файл activity_main.xml в качестве источника визуального интерфейса, можно определить следующий код в классе MainActivity :
Добавление файла layout
Но у нас может быть и несколько различных ресурсов layout. Как правило, каждый отдельный класс Activity использует свой файл layout. Либо для одного класса Activity может использоваться сразу несколько различных файлов layout.
К примеру, добавим в проект новый файл разметки интерфейса. Для этого нажмем на папку res/layout правой кнопкой мыши и в появившемся меню выберем пункт New -> Layout Resource File :
После этого в специальном окошке будет предложено указать имя и корневой элемент для файла layout:
В качестве названия укажем second_layout . Все остальные настройки оставим по умолчанию:
в поле Root element указывается корневой элемент. По умолчанию это androidx.constraintlayout.widget.ConstraintLayout .
поле Source set указывает, куда помещать новый файл. По умолчанию это main - область проекта, с которой мы собственно работаем при разаботке приложения.
поле Directory main указывает папку в рамках каталога, выбранного в предыдущей опции, в который собственно помещается новый файл. По умолчанию для файлов с разметкой интерфейса это layout .
После этого в папку res/layout будет добавлен новый файл second_layout.xml , с которым мы можем работать точно также, как и с activity_main.xml. В частности, откроем файл second_layout.xml и изменим его содержимое следующим образом:
Здесь определено текстовое поле TextView, которое имеет следующие атрибуты:
android:id - идентификатор элемента, через который мы сможем ссылаться на него в коде. В записи android:id="@+id/header" символ @ указывает XML-парсеру использовать оставшуюся часть строки атрибута как идентификатор. А знак + означает, что если для элемента не определен id со значением header, то его следует определить.
android:text - текст элемента - на экран будет выводиться строка "Welcome to Android".
android:textSize - высота шрифта (здесь 26 единиц)
android:layout_width - ширина элемента. Значение "match_parent" указывает, что элемент будет растягиваться по всей ширине контейнера ConstraintLayout
android:layout_height - высота элемента. Значение "match_parent" указывает, что элемент будет растягиваться по всей высоте контейнера ConstraintLayout
Применим этот файл в качестве определения графического интерфейса в классе MainActivity:
Файл интерфейса называется second_layout.xml, поэтому по умолчанию для него будет создаваться ресурс R.layout.second_layout . Соответственно, чтобы его использовать, мы передаем его в метода setContentView. В итоге мы увидим на экране следующее:
Получение и управлене визуальными элементами в коде
Выше определенный элемент TextView имеет один очень важный атрибут - id или идентификатор элемента. Этот идентификатор позволяет обращаться к элементу, который определен в файле xml, из кода Java. Например, перейдем к классу MainActivity и изменим его код:
С помощью метода setContentView() устанавливается разметка из файла second_layout.xml .
Другой важный момент, который стоит отметить - получение визуального элемента TextView. Так как в его коде мы определили атрибут android:id , то через этот id мы можем его получить.
Для получения элементов по id класс Activity имеет метод findViewById() . В этот метод передается идентификатор ресурса в виде R.id.[идентификатор_элемента] . Этот метод возвращает объект View - объект базового класса для всех элементов, поэтому результат метода еще необходимо привести к типу TextView.
Далее мы можем что-то сделать с этим элементом, в данном случае изменяем его текст.
Причем что важно, получение элемента происходит после того, как в методе setContentView была установлена разметка, в которой этот визуальный элемент был определен.
На прошлом уроке мы выяснили, что Activity читает layout-файл и отображает то, что в нем сконфигурировано. Теперь выясним, откуда Activity знает, какой именно layout-файл читать.
Урок был обновлен 02.02.2015
Создадим приложение для этого урока. Для этого необходимо создать модуль в проекте Android lessons. Этот проект мы создали в прошлых уроках. Если вы еще не запомнили, как создавать модули, то можно просмотреть еще раз Уроки 3 и 4.
И давайте сразу разберем один момент. Последующие уроки были написаны давно, и написаны они были под среду разработки Eclipse. Соответственно, все уроки содержат информацию для создания проекта в Eclipse.
Но Eclipse отличается от Android Studio организацией проектов/модулей. И сейчас мы разберемся, как информацию по созданию проекта в Eclipse использовать при создании модулей в Android Studio.
Инфа для создания проекта в Eclipse выглядит так:
Project name: P0051_LayoutFiles
Build Target: Android 2.2
Application name: LayoutFiles
Package name: ru.startandroid.develop.LayoutFiles
Create Activity: MainActivity
Обычно, подобный текст есть в начале каждого урока.
А для создания модуля в Android Studio нам нужна информация в таком виде
Application/Library name: LayoutFiles
Module name: p0051layoutfiles
Package name: ru.startandroid.p0051layoutfiles
Как получить из старого новое? Рассмотрим на примере этого урока. Будем брать значения для Eclipse и подставлять их в Android Studio.
Для поля Application/Library name берете значение Application name, без каких-либо изменений. Т.е. LayoutFiles.
Для Module name можно брать значение Project name, но заглавные буквы надо сделать маленькими, а нижнее подчеркивание удалить. Т.е. из P0051_LayoutFiles получаем p0051layoutfiles.
Package name – это ru.startandroid. плюc только что полученный Module name, т.е. ru.startandroid.p0051layoutfiles
Используйте эту схему во всех последующих уроках для создания модулей.
Также, в информации для Eclipse есть поле Create Activity. Его будем использовать при создании модуля, когда указываем имя Activity, в поле Activity Name
Сюда надо подставить значение из Create Activity. Обычно это всегда MainActivity.
Запомните эту инструкцию и применяйте в каждом уроке, чтобы создавать модули.
Возвращаемся к уроку.
При разработке, каждому Activity сопоставляется одноименный java-класс (наследник класса android.app.Activity). При запуске приложения, когда система должна показать Activity и в дальнейшем работать с ним, она будет вызывать методы этого класса. И от того, что мы в этих методах накодим, зависит поведение Activity.
При создании модуля мы указывали, что надо создать Activity с именем MainActivity
Мы попросили создать Activity, и среда разработки создала нам соответствующий класс (в дальнейшем мы научимся их создавать самостоятельно).
Давайте посмотрим этот класс: откроем двойным кликом файл: java\ru\startandroid\p0051layoutfiles\MainActivity.java
Смотрим java-код. Нас интересует метод onCreate – он вызывается, когда приложение создает и отображает Activity (на остальные методы пока не обращаем внимания). Посмотрим код реализации onCreate.
это вызов метода родительского класса, выполняющий необходимые процедуры, его мы не трогаем.
Нас сейчас очень интересует следующая строка:
Метод setContentView(int) – устанавливает содержимое Activity из layout-файла. Но в качестве аргумента мы указываем не путь к layout-файлу (res/layout/activity_main.xml), а константу, которая является ID файла. Эта константа генерируется автоматически в файле R.java, который мы пока трогать не будем. В этом классе будут храниться сгенерированные ID для всех ресурсов проекта (из папки res/*), чтобы мы могли к ним обращаться. Имена этих ID-констант совпадают с именами файлов ресурсов (без расширений).
Файл res/layout/activity_main.xml был создан средой разработки вместе с Activity. Его название запрашивалось на том же экране, где и название Activity (скрин выше).
В последующих уроках этот файл называется обычно main.xml, а не activity_main.xml
Откроем двойным кликом res/layout/activity_main.xml
посмотрим, что там
Запустим приложение и посмотрим, что оно нам покажет
Все верно - Activity отобразил то, что прописано в activity_main.xml.
Попробуем отобразить содержимое другого файла. Создадим еще один layout-файл, например myscreen.xml. Для этого выделим папку res/layout в нашем модуле и нажмем на ней правую кнопку мыши. В появившемся меню выбираем New > Layout resource file. Для любителей горячих клавиш есть более удобный путь: при выделенной папке res/layout нажать ALT+Insert, и там уже Enter на пункте Layout resource file.
Вводим имя файла myscreen, остальное пока не меняем, жмем OK.
В папке layout должен появиться новый файл myscreen.xml
Этот новый layout-файл должен сразу открыться на редактирование. Добавим на экран элемент Plain TextView из списка слева и через Properties изменим его текст на: «new layout file myscreen for activity».
Обязательно сохраняем (CTRL+S).
При создании нового layout-файла myscreen, среда добавила в R.java новую константу для этого файла - R.layout.myscreen. И мы теперь в коде сможем через эту константу указать на этот новый layout-файл.
Настроим так, чтобы Activity использовало новый файл myscreen.xml, а не activity_main.xml, который был изначально. Откроем MainActivity.java и поменяем аргумент метода setContentView. Замените «R.layout.activity_main», на «R.layout.myscreen» (ID нового layout-файла). Должно получиться так:
Сохраняем код (CTRL+S) и запускаем приложение (SHIFT+F10).
Теперь нам предложат подтвердить, что мы хотим запустить приложение на включенном эмуляторе.
Чтобы он при каждом запуске это не спрашивал, включите галку Use same device for future launches и жмите OK.
Видим, что теперь оно отображает содержимое из myscreen.xml, т.к. мы явно ему это указали в методе setContentView, который выполняется при создании (onCreate) Activity
Layout-файл в виде XML
Открыв в Android Studio layout файл activity_main или myscreen, вы видите его визуальное представление. Т.е. некий предпросмотр, как это будет выглядеть на экране. Снизу вы можете видеть две вкладки – Design и Text. Откройте вкладку Text
Мы видим достаточно читабельное xml-описание всех View нашего layout-файла. Названия xml-элементов - это классы View-элементов, xml-атрибуты - это параметры View-элементов, т.е. все те параметры, что мы меняем через вкладку Properties. Также вы можете вносить изменения прямо сюда и изменения будут отображаться во вкладке Design. Например, изменим текст у TextView. Вместо «new layout file myscreen for activity», напишем текст «some new text»
Сохраняем. Открываем Design и наблюдаем изменения.
Обычно авторы учебников дают содержание layout-файлов именно в xml виде. Это удобно – вы можете просто скопировать фрагмент и использовать, и не надо вручную добавлять View-элементы, бегать по Properties и настраивать все руками. Я буду делать в своих проектах так же.
Layout-файл при смене ориентации экрана
По умолчанию мы настраиваем layout-файл под вертикальную ориентацию экрана. Но что будет если мы повернем смартфон и включится горизонтальная ориентация? Давайте смотреть.
Изменим myscreen.xml. Добавим вертикальный ряд кнопок и изменим надпись.
xml-код (вы можете скопировать его и заменить им содержимое вашего layout файла myscreen во вкладке Text):
Обратите внимание - я добавил вертикальный LinearLayout и поместил в него 4 кнопки. Подробнее обсудим это на следующем уроке.
Сохраним файл, запустим приложение.
В вертикальной ориентации все ок.
Нажмем в эмуляторе CTRL+F12, ориентация сменилась на горизонтальную и наши кнопки уже не влезают в экран.
Т.е. нам необходим еще один layout-файл, который был бы заточен под горизонтальную ориентацию и в нашем случае вывел бы кнопки горизонтально.
Но как дать знать Activity, что она в вертикальной ориентации должна использовать один layout-файл, а в горизонтальной – другой? Об этом за нас уже подумали создатели Андроид. У нас есть возможность создать layout-файл, который будет использоваться приложением, когда устройство находится в горизонтальной ориентации.
Создание такого файла почти не отличается от создания обычного layout-файла. Становимся на папку res/layout и создаем новый Layout resource file. Название файла указываем то же самое: myscreen. Осталось добавить спецификатор, который даст приложению понять, что этот layout-файл надо юзать в горизонтальной ориентации. Для этого в списке спецификаторов слева снизу находим Orientation
И жмем кнопку со стрелкой вправо. Тем самым мы включили использование спецификатора ориентации. Нам надо указать, что нас интересует горизонтальная ориентация: Landscape. Выберите это значение из выпадающего списка.
Обратите внимание, что изменилось значение поля Directory name
Настройкой спецификатора мы указали, что наш новый layout-файл будет создан в папке res/layout-land, а не res/layout, как обычно. Т.е. спецификатор –land указывает на то, что layout-файлы из этой папки будут использованы в горизонтальной ориентации устройства.
Посмотрим на структуру модуля
Видим, что у нас теперь два файла myscreen: обычный и land. Можно это же увидеть в структуре папок. Для этого сверху поменяйте вид проекта с Android на Project
И вы увидите, что в модуле теперь есть папки res/layout и res/layout-land. И обе они содержат файл myscreen.
Откроем двойным кликом файл res/layout-land/myscreen и поменяем его содержимое на такой xml-код:
Вкладка Design покажет следующее:
В этом layout файле мы расположили кнопки горизонтально, чтобы они адекватно отображались в горизонтальной ориентации.
Обратите внимание на название файла сверху. Там присутствует спецификатор land, чтобы вы всегда понимали какой из двух myscreen вы сейчас редактируете.
Activity читает layout-файл, который мы указывали в методе setContentView, т.е. myscreen.xml и отображает его содержимое. При этом оно учитывает ориентацию устройства, и в случае горизонтальной ориентации берет myscreen из папки res/layout-land (если он, конечно, там существует).
Переключим ориентацию CTRL+F12.
Activity понимает, что находится в вертикальной ориентации, и использует layout-файл myscreen из папки res/layout.
Еще немного об уроках. Далее почти во всех уроках основной layout-файл будет называться main.xml. Пусть это вас не смущает, просто помните, что ваш основной файл - это activity_main.xml.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Расположение View-элементов на экране зависит от ViewGroup (Layout), в которой они находятся. В этом уроке мы рассмотрим основные виды Layout.
LinearLayout – отображает View-элементы в виде одной строки (если он Horizontal) или одного столбца (если он Vertical). Я использовал это на прошлом уроке, когда демонстрировал использование layout-файлов при смене ориентации.
TableLayout – отображает элементы в виде таблицы, по строкам и столбцам.
RelativeLayout – для каждого элемента настраивается его положение относительно других элементов.
AbsoluteLayout – для каждого элемента указывается явная позиция на экране в системе координат (x,y)
Рассмотрим эти виды
LinearLayout (LL)
Этот вид ViewGroup по умолчанию предлагается при создании новых layout-файлов. Он действительно удобен и достаточно гибок, чтобы создавать экраны различной сложности. LL имеет свойство Orientation, которое определяет, как будут расположены дочерние элементы – горизонтальной или вертикальной линией.
Сделаем простой и наглядный пример.
Project name: P0061_Layouts
Build Target: Android 2.3.3
Application name: Layouts
Package name: ru.startandroid.develop.layouts
Create Activity: MainActivity
Откроем layout-файл main.xml, и поместите в него следующий код:
Теперь корневой элемент у нас LinearLayout с вертикальной ориентацией.
Перетащите слева в корневой LinearLayout три кнопки. Они выстроились вертикально.
Теперь в Properties меняем для LL свойство Orientation на horizontal и сохраняем (CTRL+SHIFT+S) – кнопки выстроились горизонтально.
GroupView можно вкладывать друг в друга. Вложим в один LL два других. Удалите в main.xml все элементы (три кнопки) кроме корневого LL. Ориентацию корневого LL укажем вертикальную и добавим в него два новых горизонтальных LL. В списке элементов слева они находятся в разделе Layouts. Напоминаю, что вы можете перетаскивать элементы из списка не только на экран, но и на конкретный элемент на вкладке Outline.
В каждый горизонтальный LL добавим по три кнопки. Получилось два горизонтальных ряда кнопок. Убедитесь, что у горизонтальных LinearLayout высота (height) установлена в wrap_content.
TableLayout (TL)
TL состоит из строк TableRow (TR). Каждая TR в свою очередь содержит View-элементы, формирующие столбцы. Т.е. кол-во View в TR - это кол-во столбцов. Но кол-во столбцов в таблице должно быть равным для всех строк. Поэтому, если в разных TR разное кол-во View-элементов (столбцов), то общее кол-во определяется по TR с максимальным кол-вом. Рассмотрим на примере.
Создадим layout-файл tlayout.xml. с корневым элементом TableLayout
Добавим в корневой TableLayout три TableRow-строки (из раздела Layouts слева) и в каждую строку добавим по две кнопки. Результат: наша таблица имеет три строки и два столбца.
Добавим в первую строку еще пару кнопок. Кол-во столбцов для всех строк теперь равно 4, т.к. оно определяется по строке с максимальным кол-вом элементов, т.е. по первой строке. Для второй и третьей строки третий и четвертый столбцы просто ничем не заполнены.
Во вторую строку добавим TextView и Button, и текст в добавленном TextView сделаем пустым. В третьей строке сделаем то же самое. Мы видим, что эти элементы легли в третий и четвертый столбец. И т.к. TextView у нас без текста и на экране не виден, кажется что третий столбец во второй и третьей строке пустой.
Ширина столбца определяется по самому широкому элементу из этого столбца. Введем текст в один из TextView и видим, что он расширил столбец.
Я уберу элементы четвертого столбца и построю такой экран. Попробуйте сами сделать так же в качестве упражнения.
TL может содержать не только TR, но и обычные View. Добавьте, например, Button прямо в TL, а не в TR и увидите, что она растянулась на ширину всей таблицы.
RelativeLayout (RL)
В этом виде Layout каждый View-элемент может быть расположен определенным образом относительно указанного View-элемента.
1) слева, справа, сверху, снизу указанного элемента (layout_toLeftOf, layout_toRightOf, layout_above, layout_below)
2) выравненным по левому, правому, верхнему, нижнему краю указанного элемента (layout_alignLeft, layout_alignRight, layout_alignTop, layout_alignBottom)
3) выравненным по левому, правому, верхнему, нижнему краю родителя (layout_alignParentLeft, layout_alignParentRight, layout_alignParentTop, layout_alignParentBottom)
4) выравненным по центру вертикально, по центру горизонтально, по центру вертикально и горизонтально относительно родителя (layout_centerVertical, layout_centerHorizontal, layout_centerInParent)
Подробно можно почитать в хелпе.
Создадим rlayout.xml и скопируем туда такой xml-код:
Здесь у нас корневой элемент - RelativeLayout.
Получился такой экран:
Нам интересен xml-код. Сразу кратко опишу незнакомые атрибуты и их значения:
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:id = "@+id/entry"
- слово android в названии каждого атрибута – это namespace, я его буду опускать при объяснениях.
- id – это ID элемента,
- layout_width (ширина элемента) и layout_height (высота элемента) могут задаваться в абсолютных значениях, а могут быть следующими: fill_parent (максимально возможная ширина или высота в пределах родителя) и wrap_content (ширина или высота определяется по содержимому элемента). В хелпе указывается, что есть еще match_parent. Это тоже самое, что и fill_parent. По каким-то причинам, разработчики системы решили, что название match_parent удобнее, и от fill_parent постепенно будут отказываться. А пока его оставили для совместимости. Так что запомните, что match_parent = fill_parent и в дальнейшем будем стараться использовать match_parent. Позже мы еще остановимся на этом и разберем подробнее.
Сейчас вернемся к нашим элементам. В примере мы видим TextView, EditText и два Button – OK и Cancel. Давайте подробно разберем интересующие нас атрибуты.
TextView
android:id = "@+id/label" - ID
android:layout_width = "match_parent" - занимает всю доступную ему ширину (хоть это и не видно на экране);
android:layout_height = "wrap_content" - высота по содержимому;
ни к чему никак не относится
EditText
android:id = "@+id/entry" - ID
android:layout_width = "match_parent" - вся доступная ему ширина
android:layout_height = "wrap_content" - высота по содержимому
android:layout_below = "@+id/label" - расположен ниже TextView (ссылка по ID)
Button_OK
android:id = "@+id/ok" – ID
android:layout_width = "wrap_content" - ширина по содержимому
android:layout_height = "wrap_content" – высота по содержимому
android:layout_below = "@+id/entry" - расположен ниже EditText
android:layout_alignParentRight = "true" - выравнен по правому краю родителя
android:layout_marginLeft = "10dip" – имеет отступ слева (чтобы Button_Cancel был не впритык)
Button_Cancel
android:layout_width = "wrap_content" - ширина по содержимому
android:layout_height = "wrap_content" – высота по содержимому
android:layout_toLeftOf = "@+id/ok" - расположен слева от Button_OK
android:layout_alignTop = "@+id/ok" - выравнен по верхнему краю Button_OK
Вы можете подобавлять элементы и поэкспериментировать с их размещением.
Обратите внимание, что у View-элемента может не быть ID (android:id). Например, для TextView он обычно не нужен, т.к. они чаще всего статичны и мы к ним почти не обращаемся при работе приложения. Другое дело EditText – мы работаем с содержимым текстового поля, и Button – нам надо обрабатывать нажатия и соответственно знать, какая именно кнопка нажата. В будущем мы увидим еще одну необходимость задания ID для View-элемента.
AbsoluteLayout (AL)
Обеспечивает абсолютное позиционирование элементов на экране. Вы указываете координаты для левого верхнего угла компонента.
Создадим alayout.xml с корневым AbsoluteLayout
Теперь попробуйте перетаскиванием подобавлять различные элементы на экран. Они не выстраиваются, как при LinearLayout или TableLayout, а ложатся там, куда вы их перетащили. Т.е. это абсолютное позиционирование.
Открываем xml-код и видим, что для задания координат используются layout_x и layout_y.
Поначалу кажется, что это наиболее удобный и интуитивно понятный способ расположения элементов на экране - они сразу располагаются там где надо. Но это только в случае, когда вы разрабатываете для экрана с конкретным разрешением. Если открыть такое приложение на другом экране, все элементы сместятся и получится не так, как вы планировали. Поэтому этот Layout не рекомендуется использовать. И его совместимость с будущими версиями Android не гарантируется.
Есть еще много видов ViewGroup, и мы постепенно будем их осваивать. А пока нам хватит этих.
В этом уроке мы:
Рассмотрели основные виды Layout: LinearLayout, TableLayout, RelativeLayout, AbsoluteLayout
На следующем уроке:
рассмотрим подробно некоторые Layout-свойства View-элементов, которые позволяют настраивать их расположение в ViewGroup.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Для начала немного теории по экранам. Экран имеет такие физические характеристики как диагональ и разрешение. Диагональ – это расстояние между противоположными углами экрана, обычно измеряется в дюймах. Разрешение – кол-во точек по горизонтали и вертикали, которое экран способен отобразить, измеряется в пикселах.
Возьмем в качестве примера экран смартфона HTC Desire. Диагональ = 3,7 дюйма, разрешение = 800х480 пикселей.
Кол-во пикселей в одном дюйме называется dpi (dot per inch). Узнаем чему равно dpi в данном случае, вспомнив классику: c 2 = a 2 + b 2 , где с – кол-во пикселей по диагонали, т.е. вмещаемое в 3,7 дюйма. a и b – стороны экрана.
c = 3,7 * dpi
(3,7 * dpi) 2 = 480 2 + 800 2
dpi 2 = 870400 / 13,69 = 63579
dpi = 252. Т.е. в одном дюйме экрана помещается ряд из 252 пикселей.
Возвращаемся к теме урока. Рассмотрим подробно следующие параметры View элементов
Layout width и Layout height
Про ширину (layout_width) и высоту (layout_height) мы уже немного говорили на прошлом уроке. Мы можем указывать для них абсолютные значения, а можем использовать константы. Разберем подробнее эти возможности.
Абсолютные значения:
Используются следующие единицы измерения (ЕИ):
dp или dip - Density-independent Pixels. Абстрактная ЕИ, позволяющая приложениям выглядеть одинаково на различных экранах и разрешениях.
sp - Scale-independent Pixels. То же, что и dp, только используется для размеров шрифта в View элементах
pt - 1/72 дюйма, определяется по физическому размеру экрана. Эта ЕИ из типографии.
px – пиксел, не рекомендуется использовать т.к. на разных экранах приложение будет выглядеть по-разному.
mm – миллиметр, определяется по физическому размеру экрана
in – дюйм, определяется по физическому размеру экрана
Подробней о различиях и соотношениях между этими ЕИ вы можете прочесть в этом материале сайта.
Константы
match_parent (fill_parent) – означает, что элемент займет всю доступную ему в родительском элементе ширину/высоту.
wrap_content – ширина/высота элемента будет определяться его содержимым
Project name: P0072_LayoutProp
Build Target: Android 2.3.3
Application name: LayoutProp
Package name: ru.startandroid.develop.layoutprop
Create Activity: MainActivity
Открываем main.xml. Настроим корневой LinearLayout на горизонтальную ориентацию, удалим TextView, и добавим Button с шириной и высотой равной wrap_content. Она отображается на экране и ее ширина соответствует тексту на ней.
Изменим текст с «Button» на «Button with text», сохраним и посмотрим на экран.
Кнопка стала шире, т.к. ширина определяется по содержимому. Если же мы сейчас явно укажем ей ширину 250 dp, то кнопка растянется независимо от содержимого.
Теперь сделаем ширину равной match_parent. Кнопка растянулась на всю ширину родителя, т.е. LinearLayout. А LinearLayout в свою очередь занимет всю ширину экрана.
Если у нас родитель содержит несколько элементов и мы хотим, чтобы они заняли все пространство необходимо использовать параметр Layout weight – вес. Свободное пространство распределяется между элементами пропорционально их weight-значениям.
Изменим текст нашей кнопки на B1 и добавим ей соседа по LinearLayout – вторую кнопку с текстом B2. Ширину для обоих поставьте wrap_content
Займемся дележом. Если мы хотим, чтобы кнопки поделили пространство родителя поровну – то для обеих укажем weight = 1. В этом случае кнопки равны по ширине.
Обратите внимание, что не используются единицы измерения, указываются просто числа.
Если нужно, чтобы B1 занимала четверть, а B2 три четверти свободного пространства, то проставляем weight = 1 для B1 и weight = 3 для B2.
Кол-во элементов может быть любым. Добавим еще кнопку с текстом B3, weight = 2 и width = wrap_content.
xml-код получившегося экрана:
Теперь для B2 и B3 укажите weight = 0. Они больше не претендуют на свободное пространство и занимают ширину по содержимому, а B1 забирает все себе.
Разумеется, все выше сказанное применимо и для параметра высоты - height.
При использовании weight вы можете указать значение height или width = 0dp. В этом случае не будет учитываться содержимое элементов и результат будет более соответствующий коэффициентам веса.
Layout gravity
Параметр layout_gravity аналогичен выравниванию из Word или Excel. Удобнее всего продемонстрировать его с использованием FrameLayout. Я не описывал этот Layout на прошлом уроке, т.к. он совсем простой. Все помещаемые в него элементы он по умолчанию помещает в левый верхний угол и никак их не выстраивает. Нам это очень подходит для демонстрации настроек выравнивания.
Создадим grlayout.xml:
На экране видим:
Для наглядности текст кнопки отображает ее свойства. Все очевидно и несложно.
Я честно пытался понять зачем нужны значения gravity fill_* и clip_*, но так и не понял. То, что написано про них в хелпе у меня не работает. Если у вас есть сведения по этому поводу – пишите в каменты.
Layout margin
Параметры margin полностью аналогичны margin из html. Это отступ. Он может быть со всех сторон сразу, либо только с необходимых сторон. Продемонстрируем это на примере TableLayout. Создадим marginlayout.xml и нарисуем таблицу три на три с кнопками.
И на кнопке в центре будем экспериментировать.
margin = 50 dp
Вокруг кнопки со всех сторон образовался отступ = 50 dp.
margin left = 10 dp
margin top = 20 dp
Отступ слева и сверху.
margin right = 30 dp
margin bottom = 40 dp
Отступ справа и снизу.
Урок получился большой, но полезный. Думаю, это был последний урок дизайна, моделирования и верстки и дальше мы уже начнем кодить.
Стили
Если кто использовал HTML, то наверняка слышали про каскадные стили - CSS. Стили позволяют вам группировать атрибуты элементов (кнопок, таблиц, параграфов и т.д.). Далее вы просто применяете к элементам стили, и элемент рисуется с учетом всех атрибутов стиля. И нет необходимости повторять несколько раз один и тот же код для элементов, которые должны выглядеть одинаково. Особенно это удобно в случае изменения атрибутов. Вы просто меняете один раз стиль и все элементы с этим стилем меняются.
В Android тоже есть стили и они имеют точно такое же назначение. Если у вас есть несколько элементов и вам надо, чтобы они выглядели одинаково, то вы просто создаете один стиль и применяете его к нужным элементам. В принципе, вы пока можете не заморачиваться этим и начать использовать стили, когда наберетесь опыта. Ну а тем кому это интересно прямо сейчас - прошу в эту ветку нашего форума. Пользователь icamys на примере подробно разъясняет как использовать стили.
На следующем уроке:
- научимся обращаться к View-элементам из кода и менять их свойства
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
В прошлой теме мы рассмотрели создание простого приложения, который предлагает Android Studio по умолчанию и которое просто выводит на экран строку Hello Android.
Но почему у нас выводится именно эта строка? Почему у нас вообще создается именно такой визуальный интерфейс?
Выполнение приложения Android по умолчанию начинается с класса MainActivity , который по умолчанию открыт в Android Studio:
Каждый отдельный экран или страница в приложении описывается таким понятием как activity. В литературе могут использоваться различные термины: экран, страница, активность. В данном случае я буду использовать понятие "activity". Так вот, если мы запустим приложение на устройстве, то на экране мы по сути увидим определенную activity, которая предсталяет данный интерфейс.
Класс MainActivity по сути представляет обычный класс java, в начале которого идет определение пакета данного класса:
Далее идет импорт классов из других пакетов, функциональность которых используется в MainActivity:
Затем идет собственно определение класса:
По умолчанию MainActivity наследуется от класса AppCompatActivity, который выше подключен с помощью директивы импорта. Класс AppCompatActivity по сути представляет отдельный экран (страницу) приложения или его визуальный интерфейс. И MainActivity наследует весь этот функционал.
По умолчанию MainActivity содержит только один метод onCreate() , в котором фактически и создается весь интерфейс приложения:
В метод setContentView() передается ресурс разметки графического интерфейса:
Именно здесь и решается, какой именно визуальный интерфейс будет иметь MainActivity. Но что в данном случае представляет ресурс R.layout.activity_main ? Это файл activity_main.xml из папки res/layout (в принципе можно заметить, что название ресурса соответствует названию файла), который также по умолчанию открыт в Android Studio:
Файл activity_main.xml
Android Studio позволяет работать с визуальным интерфейсом как в режиме кода, так и в графическом режиме. Так, по умолчанию файл открыт в графическом режиме, и мы наглядно можем увидеть, как у нас примерно будет выглядеть экран приложения. И даже набрасать с панели инструментов какие-нибудь элементы управления, например, кнопки или текстовые поля.
Но также мы можем работать с файлом в режиме кода, поскольку activity_main.xml - это обычный текстовый файл с разметкой xml. Для переключения к коду нажмем на кнопку Code над графическим представлением. (Дополнительно с помощью кнопки Split можно переключиться на комбинированное представление код + графический дизайнер)
Здесь мы увидим, что на уровне кода файл activity_main.xml содержит следующую разметку:
Весь интерфейс представлен элементом-контейнером androidx.constraintlayout.widget.ConstraintLayout :
ConstraintLayout позволяет расположить вложенные элементы в определенных местах экрана. Вначале элемента ConstraintLayout идет определение пространств имен XML:
Каждое пространство имен задается следующим образом: xmlns:префикс="название_ресурса" . Например, в
Название ресурса (или URI - Uniform Resource Indicator) - "http://schemas.android.com/apk/res/android" . И этот ресурс сопоставляется с префиксом android ( xmlns:android ).
Зачем эти пространства имен нужны? Каждый ресурс или URI определяет некоторую функциональность, которая используется в приложении, например, предоставляют теги и атрибуты, которые необходимые для построения приложения.
xmlns:android="http://schemas.android.com/apk/res/android" : содержит основные атрибуты, которые предоставляются платформой Android, применяются в элементах управления и определяют их визуальные свойства (например, размер, позиционирование)
xmlns:app="http://schemas.android.com/apk/res-auto" : содержит атрибуты, которые определены в рамках приложения
xmlns:tools="http://schemas.android.com/tools" : применяется для работы с режиме дизайнера в Android Studio
И чтобы упростить работу с этими ресурсами, применяются префиксы. Например, дальше мы видим:
android:layout_width определяет ширину контейнера. Этот атрибут ( layout_width ) расположен в ресурсе "http://schemas.android.com/apk/res/android". И поскольку этот ресурс сопоставляется с префиксом android , то для обращения к атрибуту перед ним через двоеточие указывается префикс данного ресурса.
Значением атрибута android:layout_weight является "match_parent" . Это значит, что элемент (ConstraintLayout) будет растягиваться по всей ширине контейнера (экрана устройства).
Атрибут android:layout_height="match_parent" определяет высоту контейнера и также определен в "http://schemas.android.com/apk/res/android". Значение "match_parent" указывает, что ConstraintLayout будет растягивается по всей длине контейнера (экрана устройства).
Атрибут tools:context определяет, какой класс activity (экрана приложения) связан с текущим определением интерфейса. В данном случае это класс MainActivity. Это позволяет использовать в Android Studio различные возможности в режиме дизайнера, которые зависят от класса activity.
TextView
Текстовое поле устанавливает текст с помощью атрибута android:text .
android:layout_width устанавливает ширину виджета. Значение wrap_content задает для виджета величину, достаточную для отображения в контейнере.
android:layout_height устанавливает высоту виджета. Значение wrap_content аналогично установке ширины задает для виджета высоту, достаточную для отображения в контейнере
android:text устанавливает текст, который будет выводиться в TextView (в данном случае это строка "Hello World!")
app:layout_constraintLeft_toLeftOf="parent" : указывает, что левая граница элемента будет выравниваться по левой стороне контейнера ConstraintLayout
Обратите внимание, что этот атрибут определен в пространстве имен с префиксом app, то есть в "http://schemas.android.com/apk/res-auto".
app:layout_constraintTop_toTopOf="parent" : указывает, что верхняя граница элемента будет выравниваться по верхней стороне контейнера ConstraintLayout
app:layout_constraintRight_toRightOf="parent" : указывает, что правая граница элемента будет выравниваться по правой стороне контейнера ConstraintLayout
app:layout_constraintBottom_toBottomOf="parent" : указывает, что нижняя граница элемента будет выравниваться по нижней стороне контейнера ConstraintLayout
Стоит отметить, что последние четыре атрибута вместе будут приводить к расположению TextView по центру экрана.
Таким образом, при запуске приложения сначала запускается класс MainActivity, который в качестве графического интерфейса устанавливает разметку из файла activity_main.xml. И поскольку в этой разметке прописан элемент TextView, который представляет некоторый текст, то мы и увидим его текст на экране смартфона.
Читайте также: