Кастомизация ProgressBar в Android

    Периодически возникает потребность заменить стандартный круговой ProgressBar на какой-либо свой.

    Обычно визуальное восприятие у людей более обострено, так что сразу приведу пример нескольких вариантов ProgressBar



    На хабре обсуждались некоторые ресурсы генерации прелоадеров, можно использовать их для создания изображения, которое в последствии попадет в ProgressBar.

    Для кастомизации ProgressBar'a нужно выполнить несколько вполне тривиальных шагов:

    1. Создать Android проект
    2. Добавить в проект файл, содержащий loader (например res/drawable/loader1.png)
    3. Создать файл анимации (например res/drawable/loader1_progress.xml)

    1. <?xml version=«1.0» encoding=«utf-8»?>
    2. <animated-rotate xmlns:androidschemas.android.com/apk/res/android»
    3.   android:drawable="@drawable/loader1"
    4.   android:pivotX=«50%»
    5.   android:pivotY=«50%» />

    4. Разместить ProgressBar в Активити и сказать чтобы использовал наш ресурс анимации, созданный на предыдущем шаге (например res/layouts/)

    1. <?xml version=«1.0» encoding=«utf-8»?>
    2. <LinearLayout xmlns:androidschemas.android.com/apk/res/android»
    3.   android:layout_width=«fill_parent»
    4.   android:layout_height=«fill_parent»
    5.   android:orientation=«vertical» >  
    6.     <ProgressBar
    7.       android:indeterminateDrawable="@drawable/loader1_progress"
    8.       android:layout_height=«50dp»
    9.       android:layout_width=«50dp»>   
    10.     </ProgressBar>
    11. </LinearLayout>

    Кроме использования готовых изображений лоадеров, можно также использовать функционал android для создания лоадера вручную (например /res/drawable/custom_progress.xml)
    Рассмотрим на примере фигуры кольца. Цвета указаны в формате #aarrggbb, где аа указывает значение альфа (прозрачность).

    1. <?xml version=«1.0» encoding=«utf-8»?>
    2. <animated-rotate xmlns:androidschemas.android.com/apk/res/android»
    3.   android:pivotX=«50%»
    4.   android:pivotY=«50%»>
    5.   <shape android:shape=«ring»
    6.     android:innerRadiusRatio=«5»
    7.     android:thicknessRatio=«6»
    8.     android:useLevel=«false»>
    9.     <gradient
    10.       android:type=«sweep»
    11.       android:useLevel=«false»
    12.       android:centerY=«0.10»
    13.       android:startColor="#0020ffcc"
    14.       android:centerColor="#8820ffcc"
    15.       android:endColor="#ff20ffcc" />
    16.   
    17.     <size android:width=«18dip»
    18.        android:height=«18dip» />
    19.   </shape>
    20. </animated-rotate>


    Если у нас имеется несколько изображений одного ProgressBar

    то можно воспользоваться следующим способом (например /res/drawable/custom_progress_blue.xml):

    1. <?xml version=«1.0» encoding=«utf-8»?>
    2. <animation-list android:oneshot=«false»
    3.  xmlns:androidschemas.android.com/apk/res/android»>
    4.     <item android:duration=«100»>
    5.         <scale android:drawable="@drawable/blue_1" android:scaleGravity=«center» />
    6.     </item>
    7.     <item android:duration=«100»>
    8.         <scale android:drawable="@drawable/blue_2" android:scaleGravity=«center» />
    9.     </item>
    10.     <item android:duration=«100»>
    11.         <scale android:drawable="@drawable/blue_3" android:scaleGravity=«center» />
    12.     </item>
    13.     <item android:duration=«100»>
    14.         <scale android:drawable="@drawable/blue_4" android:scaleGravity=«center» />
    15.     </item>
    16.     <item android:duration=«100»>
    17.         <scale android:drawable="@drawable/blue_5" android:scaleGravity=«center» />
    18.     </item>
    19.     <item android:duration=«100»>
    20.         <scale android:drawable="@drawable/blue_6" android:scaleGravity=«center» />
    21.     </item>
    22.     <item android:duration=«100»>
    23.         <scale android:drawable="@drawable/blue_7" android:scaleGravity=«center» />
    24.     </item>
    25.     <item android:duration=«100»>
    26.         <scale android:drawable="@drawable/blue_8" android:scaleGravity=«center» />
    27.     </item>
    28.     <item android:duration=«100»>
    29.         <scale android:drawable="@drawable/blue_9" android:scaleGravity=«center» />
    30.     </item>
    31.     <item android:duration=«100»>
    32.         <scale android:drawable="@drawable/blue_10" android:scaleGravity=«center» />
    33.     </item>
    34.     <item android:duration=«100»>
    35.         <scale android:drawable="@drawable/blue_11" android:scaleGravity=«center» />
    36.     </item>
    37.     <item android:duration=«100»>
    38.         <scale android:drawable="@drawable/blue_12" android:scaleGravity=«center» />
    39.     </item>
    40. </animation-list>

    Код примера доступен на github.
    Если у Вас есть предложения как еще можно реализовать задуманное, не стесняйтесь, пишите.
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 27

      0
      Мне кажется, достаточно вот этого.
        0
        при более глубоком использовании очень часто падает с outofmemory, ибо оно не умеет адекватно выгружать неиспользуемое.
          0
          Расскажите детали плиз.
            0
            да без проблем.
            Ни для никого не секрет, что android не поддерживает gif анимацию.
            Вот однажды попробовал создать frame by frame анимацию про помощи AnimationDrawable. Подготовил набор картинок для анимации (25 картинок и то это сильно уменьшил, на самом деле больше нужно было). Запускаю падает с outofmemory. первый же пост со стека прояснил ситуацию, этот супермего класс грузит сразу все картинки в память, а не по необходимости.

            Да вообще последнее время разные приколы наблюдаю в ходе разработки.
            Допустим взять тот же ArrayAdapter, у него есть метод setNotifyOnChange(boolean notifyOnChange)
            Да можно установить false. но в первый раз как дернете сами notifyDataSetChanged(), оно снова станет true.
            все кроется в этом чудо методе
            Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); mNotifyOnChange = true; }

            Запостил на багтрекер ждемс… хотя с учетом что другой баг запостеный еще в декабре проигнорирован, то..)

            И да проблема насчет анимации до сих пор еще открыта, может кто посоветует что дельное?
              0
              Тогда получается первый вариант (с поворотом одной картинки) более экономичен по ресурсам.
                0
                Было бы странно, если бы он грузил по необходимости, тормозя ui.
                Но проблема актуальна, действительно
                  0
                  GIF поддерживается, но плохо. Просто его надо загружать через класс Movie. При этом на многих GIF-файлах при воспроизведении падают нативные ошибки и приложение закрывается. Еще как вариант можно открыть GIF в WebView, но проблемы при воспроизведении некоторых GIF-файлов все равно есть.
                  Писал свой декодер GIF с использованием NDK, но проблем с ним тоже было не мало. Так что если есть возможность — с гифом лучше не связываться.

                  Если в анимации кадров много, то через AnimationDrawable конечно не получится ее проиграть. Можно просто по одному загружать кадры, декодировать в Bitmap, отрисовывать и делать recycle. При этом 15-20 fps должно получится.
                    0
                    да с movie пробывал, там теряются время переходов между кадрами.
                    webview тоже не катит, проблемы с размерами да и с временем перехода тоже.
                    загружал по одному кадры на моем desire s работало превосходно, взял в офисе девайс послабее wildfire, и там дикие тормоза, поэтому тоже вариант откинул.

                    пока еще есть задачи по проекту, и поэтому к анимации возвращаюсь в свободное время, но пока ничего путного, а нужно…
                      0
                      Странно, вот как раз на wildfire все это и тестировалось. Если картинка лежит во внутренней памяти, то на ее декодинг уходит около 5 мс (кадры размером 320 х 525). Но GC при этом конечно работает не переставая.
                      Хотя если цель приложения — не только крутить анимацию, то наверное тормоза действительно будут :)
                        0
                        ага, анимация это так на пару секунд, помимо это в фоне задачи по общению с сервером крутятся, так что весело.
                        В последнее время все больше и больше задумываюсь, что возможно стоит брать таки какой-то 2d движок… Ибо написание кастомных контролов уже не везде спасает..)
                        Но черт побери, так не хочется лезть в эти дебри...)
                          0
                          Пробовал через AndEngine крутить анимацию по такому же принципу, надо буквально пару строчек кода, получается быстрее и симпатичнее.
                          Но правда если при этом поверх GLSurfaceView положить какие-нибудь стандартные контролы, то пользы от отрисовки через OpenGL ES становится немного.
                      0
                      Вот и нашли, как 2 ядра утилизировать… 1 работает, другое показывает анимацию изо всех сил.
                        0
                        надеюсь был потерян тег сарказм?)
              +1
              По моему ваш ProgressBar совсем не Progress, а лишь знак говорящий, что система занята.
                +2
                В android данный элемент называется ProgressBar, это его обычное круговое представление. Если нужен горизонтальный прогресс бар (например для индикации процесса загрузки или воспроизведения аудиофайла), тога нужно просто поменять стиль на progressBarStyleHorizontal
                  0
                  Я не придираюсь. Мне просто всегда казалось, что подобная анимация крайне не информативна. Возможно в этом направлении её и стоит «кастомизировать»…? Блин ну и слово.
                    0
                    Идея интересная. Попробую на досуге.
                +1
                Для вконтакте пишите?
                  0
                  тс… не сдавайте козыри плиз.
                    –2
                    Аааа!!! Живой миллионер в посте!
                      –1
                      Миллион, это разве не за айос приложение было?
                    0
                    Но как Вы догадались, Шерлок?!
                      0
                      Синий прогресс бар из комплекта иконок для участников конкурса приложений.
                    +1
                    Это не прогресс-бар. Прогресс бар это:
                    [|||||||||      ]
                      +1
                      Потому как не является обозначением прогресса, ни явзяется прямоугольником. Я бы назвал сабж чем-нибудь типа «busy-ring».
                        +2
                        Я бы тоже назвал как-то по другому, но увы это название контрола в Android.
                          0
                          Круговой — это ведь просто вариант indeterminate-progressbar'а, или нет? Он может быть и горизонтальным (с чередующимися полосками), но по умолчанию такой вот круглый.

                    Only users with full accounts can post comments. Log in, please.