Пользователь
0,0
рейтинг
12 февраля 2011 в 15:51

Разработка → Android nine-patch — растягиваем андроида

nine-patchРекомендации по созданию UI виджетов и некоторых блоков приложений для ОС Android предписывают нам использовать блоки с закруглёнными углами и/или с эффектом объема, отбрасывающие тени. Какие же инструменты нам дает SDK для реализации таких интерфейсов?
При описании простых векторных форм без дополнительного оформления углов и краев блока рекомендуется использовать shape формы. Если в блоке имеются сложные графические элементы по углам или с краев блока можно использовать Nine-patch изображения, о которых и пойдет речь в этой статье. На случай сложного оформления блока, например в виде единого объекта, остается использовать только фиксированное изображение, что уменьшит рамки масштабирования и не даст изменить соотношение сторон блока.

Итак, что же такое 9-path? Фактически это обычное изображение (.png), в котором края размером в 1 пиксел содержат некую служебную информацию, которую может интерпретировать графическая подсистема Android.
Эта служебная информация делится на две составляющие: информация для корректного масштабирования блока и информация об области размещения контента в блоке. При отсутствии первой – изображение будет масштабироваться целиком (всегда нужно указывать и горизонтальную и вертикальную полосы масштабирования, или не указывать обе), второй – контент будет размещаться по всей площади изображения.

Теперь о том, как задается эта информация. Верхняя и левая часть рамки задают масштабируемые области, правая и нижняя – область отображения контента. При этом прозрачные пикселы обозначают неотмеченную область, а черные (#000000) – отмеченную. Подробнее на картинке.



Теперь попробуем сделать свое 9-patch изображение. Как я писал выше, это должна быть рамка со сложными углами и/или краями, поэтому я нагуглил такую картинку:

pattern

Чтобы сделать из этой обычной картинки 9-patch можно воспользоваться любым графическим редактором, поддерживающим *.png или специальной утилитой draw9patch, которая наверняка уже лежит у вас в папке tools в месте установки Android SDK. Преимущество этой утилиты в том, что результаты масштабирования и область размещения контента наглядно показываются в окне редактора. А также утилита дает редактировать только рамку, не позволяя случайно чиркнуть на изображении.

Запустим приложение, откроем нашу рамку (File > Open 9-patch) и отметим повторяемые области и область размещения контента.

image

В правом блоке утилиты можно увидеть результат масштабирования.
Теперь необходимо сохранить полученное изображение c расширением *.9.png. Затем добавить в проект, в папку /drawable/ (если вы не предусматриваете различных вариантов изображений для разных устройств ldpi/mdpi/hdpi ) и использовать его как фон для различных элементов управления (без расширения .9).

В ОС Android nine-path используется для определения вида кнопок, полей ввода, выпадающих списков и т.д. Вы можете модифицировать эти изображения для своих разработок, взяв их из папки: android_sdk\platforms\android-8\data\res\drawable-hdpi.

image

Ссылки по теме:
Android User Interface Guidelines
Android 2d graphics
Working with NinePatch Stretchable Graphics in Android
public class android.graphics.NinePatch
Draw 9-patch tool
Слава @skkap
карма
50,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

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

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

  • +2
    А можно взять 9-path и его как-то обработать с помощью shape? Ну там скруглить края например и т.д?
    • +1
      Извините, конечно же 9-patch
    • +2
      Хм, в поле backround класса View может содержаться или цвет(solid color), или форма(shape), или 9-patch или statelist или еще что нибудь, но только одно.
      Не могу придумать ситуацию с совместным применением. Ничего же не мешает округлить углы прямо на изображении *.png.
      Но тем не менее если уж очень надо — можно поместить их друг на другом используя вложенные контейнеры и применяя к ним различные типы фона.
      • 0
        Нет, ну я имел в виду может быть можно выплюнуть на канву для shape 9-patch, а потом скруглить края, используя некие методы для shape? Или тут какая-то загвоздка?
        • 0
          Все еще не могу представить зачем может понадобиться обрабатывать таким образом изображение, но думаю если отрисовывать nine-patch на канву, то можно использовать тот же класс Paint для задания способа отрисовки. (метод draw)
          Но я такое не пробовал и не вижу причин пока.
          • 0
            Эмм… Я как понимаю, есть у нас некий ShapeDrawable — его мы можем засунуть в качестве фона для произвольного View. Если так, то можно ли скруглить края у корнеров, используя соответствующие радиусы, причем заранее залив на канву в onDraw(Canvas canvas) некую имагу?

            Лично мне это вообще в общем случае интересно, не только с 9-patch. Написав один некий Shape вы можете скругливать произвольные имаги только при помощи кода, внутри самого приложения.

            Что правда не интересно? Вообще работа с пэйнтом не очень прельщает, порадовало бы прямое выставление размеров радиусов для корнеров…
            • 0
              Пробежавшись сейчас по докам пришел к выводу, что скорее всего это можно сделать методами канвы. Попробуйте. А даже если не удастся обрезать используя Shape — всегда можно вручную обрезать углы насколько вам надо, на канве то с этим проблем нет
              • 0
                Есть класс PaintDrawable, являющийся наследником ShapeDrawable, там есть явный метод setCornersRadii(float[] radii). Вопрос следующий — возможно ли ShapeDrawable сунуть в фон?
                • 0
                  Извиняйте, можно ли PaintDrawable сунуть в фон?)
                  • 0
                    В фон View? Да, принимает, попробовал
                    • 0
                      Класс, значит таки можно выкрутиться с помощью PaintDrawable, спасибо за дискусс)
                    • 0
                      По идее в качестве бонуса, можно проверить — принимает ли Viewв фон любого произвольного наследника от Drawable) Есть мнение, что принимает)
                      • 0
                        Естественно принимает, тут и думать нечего :)
                        void setBackgroundDrawable(Drawable d)
                        Set the background to a given Drawable, or remove the background.
                        • 0
                          Ну это уже был сарказм, к тому что вы решили проверить PaintDrawable)

                          Если серьезно, то есть еще момент — как после скругления PaintDrawable себя поведет система. То есть непонятно будет ли она рендерить 9-patch как обычно когда он будет неявно присутствовать на канве View, или она реагирует только на 9-patch, который в явном виде устанавливается как фоном. В общем и целом тут, видимо, нужно экспериментировать.
                          • 0
                            Этого можно легко добиться стандартными средствами оформления, я делал так: рисуем рамку с нужным округлением, задаём границы растяжения, ставим в качестве background, а затем с помощью padding указываем размеры тени, чтобы вся тень была видима.

                            image
  • +1
    Андроминатор.
  • 0
    Жаль, что такого нет в вебе.
    • +1
      Есть нечто похожее в CSS3, но, конечно, это не универсальное решение, только для границ www.css3.info/preview/border-image/
    • 0
      Ещё как есть, всё ещё используется. Только более извращёнными способами.
  • +2
    Получается я могу, используя 9-patch, сделать резиновый фон для табов в TabWidget?

    • +1
      Резиновые фоны, резиновые контролы, резиновый интерфейс короче говоря — основное назначение 9-patch.
    • +1
      Да, только что попробовал. Можно для каждой вкладки
      mTabHost.getTabWidget().getChildAt(0).setBackgroundDrawable(getResources().getDrawable(R.drawable.bg));
      • +1
        По идее 9-patch можно подсунуть в любое View, как ни странно)
      • 0
        Прекрасно) Я точно также сейчас устанавливаю простой background. Получается, просто нужно изменить png-файл.
    • +1
      Применил 9-patch :)

      Вот фотоотчёт:


      P.S. долго не мог понять кривого растяжения фона, пока не перечитал статью и не дошел до момента, что расширение надо делать *.9.png :)
      • +1
        Рад что статья кому-то помогла :)
        • +1
          И если не сложно поделитесь своими картинками табов и кодом установки :)
          • +1
            Конечно, не вопрос :)

            private OnTabChangeListener MyOnTabChangeListener = new OnTabChangeListener()
            {
              @Override
              public void onTabChanged(String tabId)
              {
                // Всем табам устанавливаем фон NonSeled (белый)
                for(int i = 0; i < tabHost.getTabWidget().getChildCount(); i++)
                {
                  tabHost.getTabWidget().
                          getChildAt(i).
                          setBackgroundDrawable(
                          getResources().
                          getDrawable(R.drawable.nonseled));
            
                  final TextView tv = (TextView)
                          tabHost.getTabWidget().
                          getChildAt(i).
                          findViewById(android.R.id.title);
            
                  tv.setTextColor(getResources().
                          getColorStateList(R.color.nonseledcolor));
                }
            
                // Выбранному табу ставим фон Seled (чёрный)
                tabHost.getTabWidget().
                        getChildAt(tabHost.getCurrentTab()).
                        setBackgroundDrawable(
                        getResources().
                        getDrawable(R.drawable.seled));
            
                final TextView tv = (TextView)
                        tabHost.getTabWidget().
                        getChildAt(tabHost.getCurrentTab()).
                        findViewById(android.R.id.title);
            
                tv.setTextColor(getResources().
                        getColorStateList(R.color.seledcolor));
              }
            };
            


            9-patch картинки:



            habreffect.ru/files/086/a54be4e77/nonseled.9.png



            habreffect.ru/files/bcd/5563e8401/seled.9.png
            • +1
              Спасибо!
  • +2
    ожидал картинки вроде этой
    • 0
      Long android?)
  • 0
    Спасибо за статью. Как вы считаете, в связке программист — дизайнер кто должен выполнять подготовку изображений 9patch? Или лучше, чтобы это был отдельный человек-верстальщик?
  • 0
    Спасибо, ваша статья только что сэкономила мне кучу времени :)
  • 0
    начиная с какой версии SDK это работает а то что то под 2.1 у меня просто подставляет ужасно подогнанное изображения с черными линиями а в 4 все нормально.

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