Прогресс-бар закруглен с обеих сторон в Android - PullRequest
11 голосов
/ 16 января 2010

Я пытаюсь создать пользовательский индикатор выполнения в Android. Я использовал для этого следующий XML-файл (progress_bar_horizont.xml):

<?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@android:id/background">
   <shape>
    <corners android:radius="8dip" />
    <stroke android:width="2dip" android:color="#FFFF"/>
    <solid android:color="#FFFF"/>              
   </shape>
  </item>
  <item android:id="@android:id/secondaryProgress">
   <clip>
    <shape>
     <corners android:radius="8dip" />
     <stroke android:width="2dip" android:color="#FFFF"/>
     <solid android:color="#FF00"/> 
    </shape>
   </clip>
  </item>
  <item android:id="@android:id/progress">
   <clip>
    <shape>
     <corners android:radius="8dip" />
     <stroke android:width="2dip" android:color="#FFFF"/>
     <solid android:color="#FF00"/> 
    </shape>
   </clip>
  </item>
 </layer-list>

Все прекрасно работает, за исключением того, что я хотел бы, чтобы прогресс в моем индикаторе прогресса был округлен с обеих сторон. Вышеупомянутый код делает индикатор выполнения округленным с левой стороны и просто вырезанным (не округленным) с правой стороны. Это из-за тега клипа, вероятно. Не могли бы вы помочь мне в этом? Что я должен изменить, чтобы прогресс в моем индикаторе прогресса был округлен с обеих сторон?

Полный макет приведен ниже:

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical">
  <LinearLayout
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical"
  android:background="@drawable/gradient_progress"
  android:padding="10dip"
  >
   <LinearLayout
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:orientation="horizontal"
   >
    <TextView
     android:id="@+id/progress_header"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textColor="#FF000000"
     android:textAppearance="?android:attr/textAppearanceMedium"
     android:textStyle="bold"
     android:text="Uploading"               
    />
    <TextView
     android:id="@+id/progress_percent"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textColor="#FF000000"
     android:textAppearance="?android:attr/textAppearanceMedium"
     android:textStyle="bold"
     android:text="55%"         
     android:paddingLeft="10dip"
    />      
   </LinearLayout>          
   <ProgressBar
    android:id="@+id/progress_bar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_gravity="center"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:progressDrawable="@drawable/progress_bar_horizontal"
    android:maxHeight="12dip"    
    android:minHeight="12dip"    
    android:max="100" 
   />
  </LinearLayout>
 </LinearLayout>

Вот результат моих усилий: текст ссылки

Мне бы хотелось, чтобы красная полоса также имела закругленные края с правой стороны. Большое спасибо за ваши комментарии.

Ответы [ 5 ]

26 голосов
/ 21 февраля 2014

Вот обновленный ответ для времени:

Исходный код Android использует файлы Patch 9 для достижения эффекта: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/frameworks/base/core/res/res/drawable/progress_horizontal_holo_dark.xml/

Итак, начните с вашего макета XML:

<ProgressBar
    android:id="@+id/custom_progress_bar"
    style="@android:style/Widget.ProgressBar.Horizontal"
    android:indeterminateOnly="false"
    android:progressDrawable="@drawable/custom_progress_bar_horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:minHeight="13"
    android:progress="33"
    android:secondaryProgress="66" />

Вы можете перенести многое из этого в стиль XML, но это не относится к делу. Что нас действительно волнует, так это android:progressDrawable="@drawable/custom_progress_bar_horizontal", что позволит нам указать наши собственные индикаторы выполнения:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background"
          android:drawable="@android:drawable/custom_progress_bg" />
    <item android:id="@android:id/secondaryProgress">
        <scale android:scaleWidth="100%"
               android:drawable="@android:drawable/custom_progress_secondary" />
    </item>
    <item android:id="@android:id/progress">
        <scale android:scaleWidth="100%"
               android:drawable="@android:drawable/custom_progress_primary" />
    </item>
</layer-list>

Или вам не нужно использовать патч 9 для фона - например, вот простой белый фон с рамкой 1dp:

<item android:id="@android:id/background">
    <shape>
        <corners android:radius="6.5dp" />

        <solid android:color="@android:color/white" />

        <stroke
            android:width="1dp"
            android:color="@android:color/darker_gray" />
    </shape>
</item>

В Android Asset Studio есть отличный инструмент, который поможет вам сгенерировать файлы исправлений 9: http://android -ui-utils.googlecode.com / HG / актив-студия / расстояние / девять-patches.html

Пример первичного xdpi png с отступом перед инструментом: Primary progress bar
Пример вторичного xdpi png с отступом перед инструментом: Secondary progress bar

И окончательный вывод: Custom progress bar

12 голосов
/ 27 декабря 2016

Просто измените метку <clip> на <scale> следующим образом:

<scale android:scaleWidth="100%">
3 голосов
/ 18 марта 2011

Насколько я знаю, это невозможно. Потому что внутренне ClipDrawable (т. Е. Тег clip) обрезает заданную форму / рисуется с помощью canvas.clipRect(). Кстати, вы можете скопировать источник ClipDrawable из здесь и обрезать определенный путь на основе уровня прогресса.

0 голосов
/ 23 мая 2017

Окончательный округленный в обе стороны индикатор выполнения без 9-патчей: android:progressDrawable="@drawable/progress_horizontal_green"

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/progress">
    <scale android:scaleWidth="100%">
        <shape>
            <corners android:radius="5dip"/>
            <solid android:color="#33FF33"/>
        </shape>
    </scale>
</item>

0 голосов
/ 20 января 2015

Чтобы решить проблему, когда конечная графика перекрывается, когда прогресс очень низкий, я написал расширение для класса ProgressBar, которое добавляет фиксированное начальное смещение к индикатору выполнения, в то время как в остальном функционирует как обычно.

Просто вызовите setMaxWithPercentOffset () или setMaxWithOffset (), а не setMax (), передав значение, которое вы хотите добавить в качестве начального смещения для индикатора выполнения.

Если кто-нибудь решил эту проблему, не требуя начального смещения, дайте мне знать!

/**
 * This progress bar can be used when the progress bar end graphics are styled in some way.
 * In this case, the progress bar must always have a small percentage of progress, otherwise
 * the styled ends of the progress overlap each other.
 *
 */
public class EndStyledProgressBar extends ProgressBar {
    private static final int DEFAULT_START_OFFSET_PERCENT = 5;

    private int mStartOffset;
    private int mRealMax;

    public EndStyledProgressBar(Context context) {
        super(context);
        commonConstructor();
    }

    public EndStyledProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        commonConstructor();
    }

    public EndStyledProgressBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        commonConstructor();
    }

    private void commonConstructor() {
        mRealMax = super.getMax();
        mStartOffset = 0;

        setMaxWithPercentOffset(DEFAULT_START_OFFSET_PERCENT, mRealMax);

        super.setProgress(super.getProgress() + mStartOffset);
        super.setSecondaryProgress(super.getSecondaryProgress() + mStartOffset);
    }

    public void setProgress(int progress) {
        super.setProgress(progress + mStartOffset);
    }

    public void setSecondaryProgress(int secondaryProgress) {
        super.setSecondaryProgress(secondaryProgress + mStartOffset);
    }

    public int getProgress() {
        int realProgress = super.getProgress();
        return isIndeterminate() ? 0 : (realProgress - mStartOffset);
    }


    public  int getSecondaryProgress() {
        int realSecondaryProgress = super.getSecondaryProgress();
        return isIndeterminate() ? 0 : (realSecondaryProgress - mStartOffset);
    }

    public int getMax() {
        return mRealMax;
    }


    /**
     * Don't call this, instead call setMaxWithPercentOffset() or setStartOffsetInPercent()
     *
     * @param max
     */
    public void setMax(int max) {
        super.setMax(max);
    }

    /**
     * Sets a new max with a start offset (in percent) included.
     *
     * @param startOffsetInPercent start offset for the progress bar to avoid graphic errors.
     */
    public void setMaxWithPercentOffset(int startOffsetInPercent, int max) {
        mRealMax = max;
        int startOffset = (mRealMax * startOffsetInPercent) / 100;

        setMaxWithOffset(startOffset, max);
    }

    /**
     * Sets a new max with a start offset included.
     *
     * @param startOffset start offset for the progress bar to avoid graphic errors.
     */
    public void setMaxWithOffset(int startOffset, int max) {
        mRealMax = max;

        super.setMax(startOffset + max);

        setStartOffset(startOffset);

        super.setMax(startOffset + max);
    }


    /**
     * Sets a new start offset different from the default of 5%
     *
     * @param startOffset start offset for the progress bar to avoid graphic errors.
     */
    private void setStartOffset(int startOffset) {
        int newStartOffset = startOffset;

        // Ensure the start offset is not outside the range of the progress bar
        if (newStartOffset < 0) newStartOffset = 0;
        if (newStartOffset >= super.getMax()) newStartOffset = super.getMax();

        // Apply the start offset difference
        if (mStartOffset != newStartOffset) {
            int diff = newStartOffset - mStartOffset;
            super.setMax(super.getMax() + diff);
            super.setProgress(super.getProgress() + diff);
            super.setSecondaryProgress(super.getSecondaryProgress() + diff);
            mStartOffset = newStartOffset;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...