Компания
43,61
рейтинг
29 августа 2013 в 16:07

Разработка → Pixel-perfect верстка Android макетов

Разрабатывать интерфейс Android приложений — непростая задача. Приходится учитывать разнообразие разрешений и плотностей пикселей (DPI). Под катом практические советы о верстке макетов дизайна Android приложений в Layout, который совпадает с макетом на одном устройстве а на остальных растягивается без явных нарушений дизайна: выхода шрифтов за границы; огромных пустых мест и других артефактов.

UPD: Пост спорный, но много ценных советов в комментариях




UPD: Мне искренне жаль, я как маркетолог, не до конца разобрался с темой и не передал самую главную идею поста. Этот метод использовался на проекте, где заказчик предоставлял дизайн и его требованием было чтобы он выглядел максимально одинаково на всех устройствах. Исходя из этого и появился такой метод верстки, он спорный и подходит не всегда.

Большое спасибо комментаторам, за то что поправили меня и высказали свою точку зрения на правильную верстку. Если вам не нужно абсолютное совпадение макетов, резюме советов из комментариев:
  • Android Design in Action: Responsive Design видео на английском как должен тянутся дизайн Android приложений
  • Supporting Multiple Screens базовая информация о разных размерах экранов Android устройств, DPI и как адаптировать приложения под несколько экранов.
  • Designing for Multiple Screens три прекрасных урока от Google о поддержке разных разрешений экрана и DPI, рекомендую начать с него.
  • совет по масштабированию шрифтов от silentnuke
    Используйте разные значения размера шрифта для разных разрешений экрана.
    в values\dimens.xml text_size=16sp
    в values-sw600dp\dimens.xml text_size=20sp
    в values-sw720dp\dimens.xml text_size=24sp

Если нужно, присмотритесь к нашей идее в посте.


На iPhone layout задаются абсолютно и всего под два экрана iPhone 4 и iPhone 5. Рисуем два макета, пишем приложение и накладываем полупрозрачные скриншоты на макеты. Проблем нет, воля дизайнера ясна, проверить что она исполнена может сам разработчик, тестировщик или, даже, билд-сервер.

Под Android у нас две проблемы: нельзя нарисовать бесконечное число макетов и нельзя сверить бесконечное число устройств с конечным числом макетов. Дизайнеры проверяют вручную. Разработчики же часто понятия не имеют как правильно растягивать элементы и масштабировать шрифты. Количество итераций стремится к бесконечности.

Чтобы упорядочить хаос мы пришли к следующему алгоритму верстки. Макеты рисуются и верстаются под любой флагманский full-hd телефон. На остальных красиво адаптируются. Готовое приложение проверяет дизайнер на популярных моделях смартфонов. Метод работает для всех телефонов, для планшетов (>6.5 дюймов) требуются отдельные макеты и верстка.

Под рукой у меня только Nexus 4 возьмем его характеристики экрана для примера.

Макеты ненастоящего приложения-портфолио которые будем верстать (полноразмерные по клику).


Layout


Основную верстку делаем через вложенные LinearLayout. Размеры элементов и блоков в пикселях переносим с макета в weight и weightSum соответственно. Отступы верстаем FrameLayout или в нужных местах добавляем Gravity.

Для примера сверстаем ячейку списка приложений:


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 488 = 768 - 40 (левый отступ) - 40 (правый отступ) - 200 (ширина картинки) -->
    <LinearLayout
        android:id="@+id/appLstItemLayout"
        android:orientation="horizontal"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="center"
        android:weightSum="488" 
        android:background="@drawable/bg_item">

        <ImageView
            android:id="@+id/appImg"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:src="@drawable/square"/>

        <FrameLayout
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_weight="20"/>

        <!-- 130 = высота ячейки - 40 (высота звездочек) -->
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="428"
            android:gravity="center"
            android:weightSum="130">

            <FrameLayout
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="55"/>

            <TextView
                android:id="@+id/titleTxt"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="bottom"/>

            <FrameLayout
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    android:layout_weight="10"/>

            <ru.touchin.MySimpleAndAwesomeRatingBar
                android:id="@+id/appRatingBar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"/>

            <FrameLayout
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="25"/>
        </LinearLayout>
    </LinearLayout>
</FrameLayout>

Дальше нам потребуется много DisplayMetrics-магии, напишем для него static helper.

public class S {
	private static final int ORIGINAL_VIEW_WIDTH = 768;
	private static final int ORIGINAL_VIEW_HEIGHT = 1184;
	private static final int ORIGINAL_VIEW_DIAGONAL = calcDiagonal(ORIGINAL_VIEW_WIDTH, ORIGINAL_VIEW_HEIGHT);

	private static int mWidth;
	private static int mHeight;
	private static int mDiagonal;
	private static float mDensity;

	static {
    	DisplayMetrics metrics = TouchinApp.getContext().getResources().getDisplayMetrics();
    	mWidth = metrics.widthPixels;
    	mHeight = metrics.heightPixels;
    	mDiagonal = calcDiagonal(mWidth, mHeight);
    	mDensity = metrics.density;
	}

	public static int hScale(int value){
    	return (int)Math.round(value * mWidth / (float) ORIGINAL_VIEW_WIDTH);
	}

	public static int vScale(int value){
    	return (int)Math.round(value * mHeight / (float) ORIGINAL_VIEW_HEIGHT);
	}

	public static  int dScale(int value){
    	return (int)Math.round(value * mDiagonal / (float) ORIGINAL_VIEW_DIAGONAL);
	}

	public static  int pxFromDp(int dp){
    	return (int)Math.round(dp * mDensity);
	}

	private static int calcDiagonal(int width, int height){
    	return (int)Math.round(Math.sqrt(width * width + height * height));
	}
}

1184 это высота Nexus 4 без кнопок, 768 — ширина. Эти значения используются, чтобы выяснить во сколько раз высота и ширина устройства, на котором запущено приложение, отличаются от эталонного.

ScrollView и List

Подход с weightSum не примемим к прокручивающимся элементам, их внутренний размер вдоль прокрутки ничем не ограничен. Для верстки ScrollView и List нам потребуется задать их размеры в коде (130 — высота элемента списка).

if (view == null) {
    view = mInflater.inflate(R.layout.item_app_list, viewGroup, false);
    view.setLayoutParams(new AbsListView.LayoutParams (ViewGroup.LayoutParams.MATCH_PARENT, S.dScale(130)));
 }

И дальше можно применять трюк с weightSum.

Картинки


Размер иконок приложений задается в коде:

view.findViewById(R.id.appImg).setLayoutParams(new LinearLayout.LayoutParams(S.dScale(240) - S.pxFromDp(20), S.dScale(240) - S.pxFromDp(20)));

Где 240 высота элемента списка, 20 высота отступа сверху и снизу.

Шрифты


Андроид не предоставляет единицу измерения пропорциональную размеру экрана. Размеры шрифтов рассчитываем на основании диагонали устройства:
textSizePx = originalTextSizePx * (deviceDiagonalPx / originalDeviceDiagonalPx )

Да, размеры шрифта придется задавать в коде (36 размер шрифта в пикселях на оригинальном макете).
titleTxt.setTextSize(TypedValue.COMPLEX_UNIT_PX, S.dScale(36));

Советы по работе с графикой


1. Используйте Nine-patch везде где возможно, где невозможно — перерисуйте дизайн.
2. Простые элементы рисуйте с помощью Shape
3. Избегайте масштабирования изображений в runtime

Nine-patch это графический ресурс содержащий в себе мета-информацию о том как он должен растягиваться. Подробнее в документации Android или на Хабре.

Nine-patch нужно нарезать под все dpi: ldpi mdpi tvdpi hdpi, xhdpi, xxhdpi. Масштабирование ресурсов во время работы приложения это плохо, а масштабирование Nine-Patch приводит к неожиданным артефактам. Ни в коем случае не задавайте в Nine-patch отступы, они оформляются отдельными элементами layout, чтобы растягиваться пропорционально контенту.



Shape


Если ресурс легко раскладывается на простые геометрические фигуры и градиенты лучше вместо нарезки использовать xml-shape. Для примера нарисуем фон рамку вокруг проекта в списке, которую мы выше нарезали как Nine-patch.



<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
	<!-- "shadow" -->
	<item>
    	<shape android:shape="rectangle" >
        	<corners android:radius="5px" />
        	<solid android:color="#08000000"/>
    	</shape>
	</item>
	<item
    	android:bottom="1px"
    	android:right="1px"
    	android:left="1px"
    	android:top="1px">
    	<shape android:shape="rectangle" >
        	<corners android:radius="4px" />
        	<solid android:color="#10000000"/>
    	</shape>
	</item>
	<item
    	android:bottom="2px"
    	android:right="2px"
    	android:left="2px"
    	android:top="2px">
    	<shape android:shape="rectangle" >
        	<corners android:radius="3px" />
        	<solid android:color="#10000000"/>
    	</shape>
	</item>
	<item
    	android:bottom="3px"
    	android:right="3px"
    	android:left="3px"
    	android:top="3px">
    	<shape android:shape="rectangle">
        	<corners android:radius="2px" />
        	<solid android:color="#ffffff"/>
    	</shape>
	</item>
</layer-list>


Картинки

Масштабирование графики силами Android трудоемкая и затратная по памяти операция. Картинки внутри Android обрабатываются как bitmap. Например, наш логотип в размере 500x500 со сплешскрина распакуется в bitmap размером 1мб (4 байта на пиксель), при масштабировании создается еще один bitmap, скажем в 500кб. Или 1,5мб из доступных 24мб на процесс. Мы не раз сталкивались с нехваткой памяти в богатых на графику проектах.

Поэтому картинки которые нельзя описать ни Nine-patch ни Shape я предлагаю поставлять в приложении как огромный ресурс в папке nodpi и при первом запуске масштабировать изображение до нужного размера и кешировать результат. Это позволит нам ускорить работу приложения (не считая первого запуска) и уменьшить потребление памяти.

Для сложных ресурсов подгружаемых с сервера (иконки приложений на наших макетах) идеальный вариант если сервер будет отдавать картинки любого размера. Как, например, сделано на проекте Stream. Приложение просчитывает нужный размер картинки для экрана смартфона, где запущено, и запрашивает их у сервера.

http://<secret_domain>/media/img/movies/vposter/plain/22741680/<любая ширина px>_<любая высота px>.jpg


P.S. советы придуманы и основа поста написаны нашим Android-гуру Лешей, огромное ему спасибо!

А как вы рекомендуете верстать макеты под Android? Сколько макетов рисует дизайнер? Как обращаетесь с графическими ресурсами?


Подписывайтесь на наш хабра-блог (кнопка справа вверху). Каждый четверг интересные статьи о мобильной разработке, маркетинге и бизнесе мобильной студии. Следующая статья (5 сентября) «C# async на iOS и Android»
Автор: @junk
Touch Instinct
рейтинг 43,61
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Комментарии (83)

  • 0
    Спасибо за статью
  • +2
    [offtopic] А у вас много дискового пространства на media.omlet.ru? А то любой начинающий кулхацкер нагенерит вам картинок по самое нехочу :) [/offtopic]
    • 0
      а вы правы, убрал на всякий
      • +1
        Если бы lotas не сказал, я бы и не догадался. А теперь прям аж захотелось подставить вместо sеcret_domain тот самый секретный домен из предыдущего комментария… (=
  • +6
    Размеры в weight? Вы издеваетесь?
    • –7
      а что не так? (ну и занудства ради там не размеры а приоритет, с пикселями он совпадает для простоты)
    • 0
      Ну вообще-то в некоторых ситуациях это довольно полезный атрибут.
      Надо выделать каждому дочернему слою одинаковое или соразмерное пространство? Пожалуйста.

      Надо заставить элемент заполнить все пространство по центру, не тронув при этом крайние элементы? Запросто.
      • +2
        В определенных случаях полезно, но в данном конкретном, это просто издевательство, по производительности будет бить ужасно. Тем более не понятно зачем такие извраты.
  • +11
    Либо я не понял проблемы, которую Вы пытаетесь решить, либо Вы не читали гайдов.
    Зачем хелпер, если все, что создается вполне можно создавать в xml и размеры указывать там?
    Шрифт масштабировать под размер экрана — это вообще что и зачем?!
    Все что я понял, Вы пытаетесь создать одинаковую картинку, растянутую на разные размеры экранов. Это полностью противоречит всем правилам разработки под андроид.
    • –1
      а можно ссылочку на гайды, конкретный раздел который нужно почитать?

      Советы основаны на нашем опыте разработки нескольких сложных Android приложений, возможно, у вас другой опыт. Расскажите, о нем, кстати.
    • –1
      Шрифт масштабировать под размер экрана — это вообще что и зачем?!

      У меня подобная проблема, надо в приложении выводить текст пропорционально размеру экрана, если этого не делать, то надписи на больших экранах кажутся слишком мелкими, или наоборот — нормальные на больших, но слишком крупные на маленьких устройствах. В статье я увидел вариант решения, спасибо автору! Он не идеальный, но хоть какой-то.
      А как надо? Как решить задачу красиво, по правилам разработки под андроид?
      • +2
        Используйте разные значения размера шрифта для разных разрешений экрана.
        в values\dimens.xml text_size=16sp
        в values-sw600dp\dimens.xml text_size=20sp
        в values-sw720dp\dimens.xml text_size=20sp

        Все прозрачно и понятно.
        • +1
          спасибо!
          • +1
            не за что, правда опечатку заметил.
            В values-sw720dp конечно же 24. А если нужно 20, то папку values-sw720dp создавать не нужно, подтянется из values-sw600dp
  • +5
    Использовать вложенные LinearLayout и FrameLayout для отступов?
    Месье знает толк в извращениях.

    RelativeLayout позволит сразу разместить все элементы в одном ViewGroup, без накладных расходов на компоновку, перерисовку и измерение. А если очень нужна возможность задавать пространство, есть Space, в котором нет лишних расходов на перерисовку.
    • +4
      вот и я про то же — не слышал чтоб layout_margin маркировали deprecated
    • 0
      Это тот Space который с АПИ 14? Чем плох обычный View? Это конечно в том случае, если margin и padding не подходят.
      • 0
        Это тот Space, который есть в Support Library v7
        View хуже тем, что работает медленнее, а Space специально облегчен для использования в качестве отступов.
        • 0
          И правда :) Заглянул в исходники, никогда бы не подумал что в draw() пустой вьюхи делается столько всего.
          пс: по-хорошему вьюха должна бы наследовать спейс и переопределять нужные его методы, а то из иерархии классов совсем не очевидно что есть что-то легковеснее вьюхи.
          • 0
            ну как бы менять так кардинально иерархию, спустя столько версий, было бы ужасной идей.
            • 0
              Естественно, я имел ввиду если сначала так делать.
  • –1
    Просто интересно, есть ли какой-то другой вариант написания разметки кроме XML?
    • +1
      Нормального — нет.
      А так — создаёте вьюшки в рантайме, добавляете нужные аттрибуты и фигачите в layout. Но зачем?
      • +1
        Никакой альтернативы а-ля html?
        • +4
          Сложно понять, что вы хотите. Layout XML это и есть a la HTML. Даже со стилями.
    • +1
      В коде, но зачем? Чем вас xml не устраивает?
  • +4
    Omg. Для такой простой верстки вы создали извращенную магию. Почитайте про RelativeLayout и фреймворк ресурсов
  • +10
    — Автор почему-то по умолчанию считает, что дизайн макета нужно верстать пропорционально под все телефоны, хотя это совершенно необязательно. Какие-то элементы (кнопки, тулбары) вполне могут оставаться постоянного размера (с учетом dpi, разумеется), какие-то (например, текстовое поле для текстового же редактора, либо SurfaceView для видео) таки действительно нужно масштабировать под максимум свободного места на экране. Все зависит от задачи.
    — Если у меня экран больше в два раза, это не значит, что я хочу видеть звездочки в ListViewItem в два раза больше. Это означает, что я хочу видеть в два раза больше элементов на экране, так что ListViewItem вообще не надо масштабировать.
    — Если автор все же озадачился масштабированием всего и вся пропорционально экрану, то он должен озадачиться также масштабированием шрифтов, иначе они-таки вылезут за границы элемента. В статье об этом почему-то ни слова.
    — Если автор все же озадачился масштабированием всего и вся пропорционально экрану, то у него все равно это получится некрасиво, ибо нужно учитывать, что пропорции у разных экранов — разные. Если везде просто домножать на dScale, оно поплывет, если же отдельно высоту на vScale, а ширину на hScale — у контролов разъедутся соотношения сторон.
    — Вложенные LinearLayout нужно использовать очень осторожно. При большой вложенности обсчет прорисовки начинает жутко тормозить, так что с увеличением сложности дизайна нужно рассматривать варианты с RelativeLayout или рисованием кастомного контрола на Canvas.

    Леша, ты меня расстраиваешь =/
    Толик, запятые, ну сколько раз я тебе говорил…
    • –3
      Володя, спасибо, подробный и обоснованный коментарий.

      > Если автор все же озадачился масштабированием всего и вся пропорционально экрану, то он должен озадачиться также масштабированием шрифтов, иначе они-таки вылезут за границы элемента. В статье об этом почему-то ни слова.

      Читаем еще раз :) или ctrl+f шрифты

      Поделись, как у вас в StudioMobile принято, какие макеты рисует дизайнер, как верстаете, как проверяете?
      • 0
        Про шрифты не заметил, согласен.

        На данный момент на моем проекте, увы, не идет никакой работы над дизайном под Android, за другие проекты и, соответственно, дизайнеров сказать не могу. По существующему коду — мелкие элементы (кнопки там всякие) имеют фиксированный размер под три разных типа экранов, layout-ы растягиваются под weight, в общем как обычно, экзотических сложностей я тут пока не обнаружил (= Разве что поотрывать руки тем, кто сделал три одинаковых xml в разных размерах (вместо того, чтобы заюзать стили), но это уже из другой оперы…
    • +7
      Странно выглядит этот комментарий от работающего там же человека )
      • –2
        давно нет
      • 0
        Хабрапрофиль устарел, я там уже полгода не работаю.
  • +7
    Перечитал статью еще раз. Вся статья — один большой косяк. Все кроме совета про использования nine-patch и xml для графики — вредные советы. Я бы спасался бегством от такого «гуру».
    • 0
      и ваша точка зрения, как надо?
      • +5
        На мой взгляд:
        1. Дизайнер рисует 2-3 макета (скажем телефон и планшет), может еще пограничное что-то, например, nexus 7.
        2. Макеты могут очень сильно отличаться, но тут фрагменты в помощь и папки layout-sw600dp например.
        3. Верстаются макеты, а элементы тянутся по отдельности «по смыслу». Т.е. масштабируется не все подряд, а только то, что необходимо.
        4. Контроллы на всех телефонах одинакового физического размера и размеры задаются в dp.
        5. Шрифты задаются в sp, что бы дать возможность пользователю в настройках телефона поставить крупный шрифт например. Вдруг плохое зрение у пользователя?
        6. В комментариях много уже написано, про избыточную вложенность примеров.
        7. Задание размеров чего бы то ни было в коде — огромная редкость. И в этом случае все равно используются размеры из файлика dimen.xml.

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

        А вообще смотрите DevBytes и Android Design in Action на youtube. Там много советов по best practice верстки под андроид.
    • +2
      Xml-drawables, особенно многослойные, зачастую, рисуются намного медленнее и требуют больше ресурсов, чем 9-patch соответствующего формата. Так что я бы остерегся называть совет по-максимуму использовать xml-drawables не вредным.
      • 0
        Тут есть о чем разговаривать. Вы правы когда-то стоит, когда-то — нет. Но это не так однозначно, как все остальное на мой взгляд.
  • +2
    Вложенные LinearLayout? Nine-patch не надо растягивать?

    Сомнительная статья…
  • +2
    Тут уже много сказали. Я бы от себя добавил, что, вкладывая друг в друга LinearLayout'ы c весами (nested weights), вы каждый раз убиваете милого утёнка. И чем больше вложенность, тем больше утят погибает экспоненциально.
    • –1
      А почему? и как правильно?
      • +3
        В документации, а также в различных докладах, разработчики андроид говорят, что каждый раз, когда вы используете layout_weight, измерение компонентов происходит в два прохода, соответственно, это быстро растет, когда у вас вложенные LinearLayouts. Как правильно — зависит от ситуации. Обычно стремятся минимизировать вложенность, например, помощи RelativeLayout.
        • 0
          Ты умеешь делать пропорциональное деление экрана с помощью RelativeLayout? Научи меня
          • +1
            Даша, если тебе нужно сделать пропорциональное деление — используй веса, почему нет, я кажется не отговариваю их использовать, я отговариваю их нестить друг в друга. А если у тебя все настолько сложно, что нужно пропорционально поделить пропорционально поделенное, то, может быть нужно использовать другой layout? GridLayout, например?
            • –2
              Не обо мне речь. Данную конкретную задачу RelativeLayout не решает и никоим образом не может оптимизировать.
              Возможно, ты хотел сказать, что дизайнеру надо придумать такое представление экрана, чтобы и смотрелось хорошо, и версталось без вложенных весов. Это я тоже так думаю, да )
              • +4
                Ну, как сказать… это не совсем то, что я имел ввиду. Далеко не всегда мы можем заставить дизайнера что-то изменить, иногда дизайны идут «сверху», с этим ничего не поделаешь. Если есть возможность работать напрямую с дизайнером, да еще и знакомым с гайдлайнами — это чудо, как хорошо, но, такое бывает не всегда. Я говорил, что мы, как _разработчики_ обладаем достаточным арсеналом, чтобы любую задачу реализовать несколькими способами, и это наша ответственность выбрать наиболее оптимальный. Ты зачем-то прицепилась к RelativeLayout, который я привел как пример, но это далеко не единственный layout, который есть, их больше, для разных целей, кроме того, на крайний случай, в нетривиальной ситуации, можно написать свой, который будет делать твою узкую задачу в 100 раз лучше и быстрее, чем существующий универсальный с кучей костылей. (минусую, если что, не я :)).
  • +5
    И это вы называете «без боли»?
  • +3
    В нашем проекте мы с дизайнером работаем так:

    Дизайнер предоставляет макет с отступами и размерами (dp), шрифтами (sp) и цветами в разрешении xhdpi.
    Затем с помощью android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html генерируются 9patch под все dpi. Косяки генератора исправляются вручную.
    Все цвета вынесены в colors.xml, все простейшие drawable заданы в xml. Все свойства виджетов заданы в styles.xml и применяются в качестве темы оформления.
    Под планшеты создаются отдельные layout, которые вмещаются больше инфы и т.д. (с применением фрагментов).

    Используется RelativeLayout по максимуму, где только можно. Поскольку вложенные вьюшки, а тем более LinearLayout очень сильно сказываются на производительности, а на телефонах с 2.3.3 вообще вызывают stackoverflow exception при отрисовке, если приложение обладает достаточно мощным интерфейсом с кучей элементов.

    Соответственно, под все dpi все прекрасно тянется, шрифты увеличиваются вместе с системными, как и положено.

    Не совсем понял смысла статьи, т.к. в гайдах все описано, как создавать дизайн под различные экраны и плотность точек.
    • –2
      Можно ссылку на гайды «как создавать дизайн под различные экраны и плотность точек»?

      И было бы интересно посмотреть на пример макета, может у себя попробуем внедрить такой формат.
      • +1
        Когда-то, давным давно, года три назад, просьба предоставить ссылку на какой-то гайд по Андроиду была вполне нормальным явлением. Информации было мало, и мы тогда собирали ее буквально по крупицам, обменивались опытом с коллегами, молились на одинокие статьи Романа Ги, Кирилла Мотье. Но сейчас, в 2013… Информации столько, она разжевывается так подробно, что только ленивый ее не найдет. d.android.com, d.adnroid.com/design, каналы Android Developers c часами материала с IO, DevBytes, ADIA, многочисленные комьюнити в G+, странички известных людей в G+…
      • +2
        Ссылки вам написали выше. Удивительно, что вы взялись за разработку приложения, не изучив гайды. Я думал, уже прошло время, когда приложения делались абы как.
  • +1
    layout_weight это хорошая штука, но пренебрегать ей не надо — слишком много телефону пересчитывать приходится перед показом. Насчёт px вообще не понял зачем? Есть ведь dp и sp чтоб как раз этими пересчётами не заниматься
  • +7
    Ничего себе вы тут на советовали:

    — Кучу костылей для масштабирования размеров разметки и шрифтов, когда специально для этого есть dp, sp и куча идентификаторов ресурсов.
    — Усложнение кода, там где это не надо.
    — Использование весов там где не нужно, будет страдать производительность
    — Лишние вьюшки, которые там совсем не нужны. Можно спокойно выкинуть 2-3-4. А если экран у устройства большой, и видно скажем 10 элементов в списке, это мы получим 20-30-40 сэкономленных вью.
    — как работает gravity, из вашей разметки я вижу вы тоже не понимаете. Там только первый по делу, остальные 3 не нужны.
    — что будет если повернуть телефон?

    Еще и заголовок — «Верстка Android макетов без боли»

    >Разработчики же часто понятия не имеют как правильно растягивать элементы и масштабировать шрифты.
    значит это не разработчик.

    >Nine-patch нужно нарезать под все dpi: ldpi mdpi tvdpi hdpi, xhdpi, xxhdpi
    Сильно уж однозначный совет. Не обязательно пилить под все, вообще не помню когда последний раз видел ldpi.
    Да и ресурсы в основном только выборочно раскидывают, в зависимости от типа.
    Или тот же xxhdpi, если для него не будет, это не сильно критично. А вот иконку приложения туда кинуть нужно обязательно.
    Тоже самое и tvdpi. TvDpi это только телики и Nexus 7, на нем в полне нормально выглядят иконки с hdpi

    В общем нужно что бы были картинки для mdpi, hdpi, xhdpi, и иконка приложения в xxhdpi.
    Остальные по желанию, и то имеет смысл только, если ваш дизайнер «вылизывает» иконки, и подгоняет каждый пиксел.

    >наш логотип в размере 500x500 со сплешскрина
    это вам не айфон, тут приложения моментально запускаются. Сплэшсрин на андроиде не используется.

    >при первом запуске масштабировать изображение до нужного размера и кешировать результат.
    Если картинка прям такая огромная, что у вас валится с OOM, то во первых неплохо бы
    1. поработать над картинкой и уменьшить ее размер. Есть куча способов это сделать. Начиная от оптимизаторов пнг, заканчивая сохранением с уменьшением палитры.
    2. загружать в память уменьшенную картинку, для этого не нужно ничего и никуда кэшировать. Вот тут подробнее: developer.android.com/training/displaying-bitmaps/load-bitmap.html

    Вывод: гайдланы не читали, андроид видим впервые, зато даем советы другим.
    • +3
      С удовольствием подпишусь под каждым словом. Интересно, что при общем и заслуженном негативе в комментариях, сама статья ушла далеко в плюс, что значит, многие воспользуются этими «полезными» советами…
      • +2
        Это ещё не «далеко в плюс», но да, хабр такой… непритязательный.
      • +3
        Если статья уйдёт далеко в минус — её могут спрятать в черновик. В комментариях много полезных советов есть, жаль будет, если они пропадут вместе со статьей.

        Так что по мне лучше уж так, чем «справедливая кара» за вредные советы.
    • –3
      >это вам не айфон, тут приложения моментально запускаются.
      спасибо посмеялся, вот для затравки www.google.com/search?q=App+takes+too+long+to+start-up&oq=App+takes+too+long+to+start-up
      может приложения и работают быстрее?

      >Если картинка прям такая огромная, что у вас валится с OOM, то во первых неплохо бы
      24mb на процесс, 20 картинок 500x500 хватит, неоднократно сталкивались с такой ситуацией

      А подскажите, какие Android приложения вы сделали? Возможно, слишком разный опыт.
      • –3
        • 0
          Этот линк должен что-то означать? Может, конечно, у нас Гуглы разные, но тем не менее:
          android App takes too long to start-up: Результатов: примерно 1 310 000 000
          iphone App takes too long to start-up: Результатов: примерно 1 410 000 000
          Впрочем, в любом случае, выборки эти сильно разбавлены результатами, не имеющими отношения к поставленному вопросу, так что вопрос об их репрезентативности даже не стоит.

          И, кстати, я не в курсе, как там все работает под iOS, но в Андроиде приложения действительно запускаются крайне быстро. Другое дело, что запуск отдельно взятой тяжелой Activity может затянуться, но это уже совсем другая история. В тех приложениях, в разработке которых я принимал участие, в большинстве случаев сплэш-скрин использовался для того, чтобы пару секунд пропиарить логотипчик компании. И только в некоторых случаях там выполнялась какая-то заметная и затратная по времени работа, вроде загрузки .obb-файлов (если они по какой-то причине не подтянулись с маркета сами).
      • +2
        Простите, мне показалось, или вы действительно только что привели в качестве аргумента, что приложения медленно запускаются ссылку на вопрос на SO, где человек загружает 50 экранов в ViewFlipper при запуске приложения? Вы нас троллите?
        • –3
          да, ссылка так себе ~__~ но вот получше stackoverflow.com/questions/8642730/splash-screen-in-android-application

          Мне показалось бредовым утверждение «на android нет поддержки splash screen, потому что приложения запускаются мгновенно» но это не так, чудес не бывает. Висит черный экран, когда на ios есть возможность впихнуть туда картинку.

          Или гугл пишет «If your application has a time-consuming initial setup phase, consider showing a splash screen or rendering the main view as quickly as possible, indicate that loading is in progress and fill the information asynchronously. In either case, you should indicate somehow that progress is being made, lest the user perceive that the application is frozen.»
          developer.android.com/training/articles/perf-anr.html

          Хотя что это я :) Спор не о чем.
          • +1
            Сплэшскрин, да, имеет смысл, если там действительно надо первоначально МНОГО сделать, как то заполнить базу, сделать 50 запросов на сервер, что бы подготовить все и тд. Но практика показывает, что сплэшскрин ставят после айфона, просто, потому что, потому.
            • –2
              что-то мы не туда ушли, я нигде не говорил, что сплеш-скрин нужен в Android приложениях, а приложение что в статье никогда не существовало, это три картинки для примера.

              У меня нет под рукой android, но стало интересно, как происходит на нем загрузка инстаграмма или фейсбука, например. Что происходит после нажатия на иконку.
              • +2
                У инстаграмма нету, фэйсбук там что то первоначально делает. На фэйсбук бы я не стал ориентироваться, так как они совсем не показатель, то они вебвью используют, то 600+ вью создают, проблем у них много, приложение тормозное, вот только недавно, кое как они начали что то исправлять.

                Ну не чему там тормозить, если вы только не грузите кучу данных. Да даже если на 100-200ms, задержка, можно тот самый «черный» экран облагородить, что то совсем легкое, цвет, например, поменять и тд. Рулится все из темы.
      • +2
        > спасибо посмеялся, вот для затравки www.google.com/search?q=App+takes+too+long+to+start-up&oq=App+takes+too+long+to+start-up
        Во первых там не понятно, что такое по ссылке.
        Во вторых сама активити по себе не сильно тяжелая, если старт долгий, значит вы чет там делаете не так. Может сплэшскрин в основном треде грузите. Может что то еще плохое делаете. Можно сделать замеры, посмотреть в логат, может там хореограф ругается и тд. Сплэшскрин не нужен, для такой простой проги.
        В третьих, у нас есть(у вас есть) простая активити, так вы тратите время на создание временной + время на загрузку здорового битмапа + еще скорее все таймер стоит. За то время пока там сплэшскрин все это делает, активити уже 5-10 раз успеет запуститься.

        >24mb на процесс, 20 картинок 500x500 хватит, неоднократно сталкивались с такой ситуацией
        Написано было про одну картинку. ОК 20 картинок, в чем проблема?
        1. Делаете кэш в памяти
        2. загружаете сразу с нужными Bitmap.Options, что бы не занимало много памяти. Еще можно поиграть с Bitmap.Config.RGB_565
        3. выгружаете не нужные, по мере заполнения
        Подробнее здесь: developer.android.com/training/displaying-bitmaps/index.html

        Не можете осилить сами, возьмите библиотеку:
        github.com/nostra13/Android-Universal-Image-Loader
  • 0
    Из личных наблюдений: weight — вещь весьма относительная. Например, если создать layout типа такого:

    LinearLayout
    Button android:weight=«1»
    Button android:weight=«1»
    /LinearLayout

    то это еще не значит, что кнопки будут строго одинакового размера.
    P.S. Что-то тэг code съедается, оставлю так
    • 0
      будут, если вы им обеим поставите layout_width=«match_parent»
      • +2
        вообще-то 0dp стоит ставить для улучшения производительности, если про горизонтальный linearlayout идет речь (если вертикальный, то соответственно высоте 0dp)
        • 0
          Да, действительно, вы правы, спасибо. Я забыл об этом. Суть моего коммента была, что не «wrap_layout», ибо тогда они не будут одинаково растянуты в зависимости от их содержимого. Держите плюсик.
          • 0
            Lint он всегда подсветит в разметке, если забудете :)
            • 0
              Если б все еще lint смотрели, жить было бы легче. А то порой открываешь проекты, которые приходят на поддержку, а там банально используется api старшей версии, хотя минималка другая, а ведь lint это сразу говорит :(
          • 0
            Спасибо всем.
  • 0
    но ведь можно размер текста в dp
    • 0
      Вы хотели сказать в «sp»? :)
      • 0
        Да, прошу прощения, конечно в sp.
  • +1
    Ребята, вам стоит срочно задуматься об изменении подхода. То что вы советует, это просто ужас
    Ладно еще вложенные вьюхи с весом, которые бьют по отрисовке.
    Так у вас же по коду, куча магических чисел, а что если нужно изменить верстку? Правки xml уже недостаточно, нужно бегать по коду и править эти магические числа. А как же адаптивная верстка? Зачем просто растягивать?

    У нас в компании делаются макеты для xhdpi hadnset (640x960), делается нарезка для mdpi, hdpi, xhdpi. Далее в xml проставляются необходимые отступы, шрифты и прочее согласно mdpi. При адаптации для таблеток, делаются доп layout некоторых экранов, где необходим. Или в самом простом случае, просто dimen.xml с размерами для таблеток.
    Также не стоит забывать про фрагменты.

    PS: почитайте все-таки гайдлайны, посмотрите devbytes и т.д.

    Ну и почитайте гайдлайны, посомтрите вуминеуы
    • 0
      Какая еще адаптивная верстка, если часть верстки находится в коде, а изменения dp/sp/px и любых других измерительных чисел происходит при помощи вспомогательного класса?
      • 0
        А я о чем и написал?

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое Разработка