Как программно создать или изменить drawable из линий разных цветов

Я должен нарисовать линию 3dp, чтобы представить завершение уровня в игре викторины.

эта линия должна иметь 2 цвета. Например, если пользователь завершил 40% уровня, линия будет Красной для первых 40% линии, а остальные 60% будут серыми.

мне удалось сделать это с помощью drawable:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="line" >
            <size android:height="3dp" android:width="40dp"/>
            <stroke
                android:width="1dp"
                android:color="#FFFC10" />
        </shape>
    </item>
    <item android:left="40dp">
        <shape android:shape="line" >
            <size android:height="3dp" android:width="60dp" />
            <stroke
                android:width="1dp"
                android:color="#DDDDDD" />
        </shape>
    </item>
</layer-list>

и затем я отображаю его с помощью ImageView:

<ImageView
                android:id="@+id/row_completion_bar"
                android:src="@drawable/completion_bar"
                android:layout_width="100dp"
                android:layout_height="3dp" />

... но теперь я, конечно, должен иметь возможность изменить этот 40%/60% рацион в зависимости от завершения пользователя actuel.

первый вопрос: каков наилучший наиболее эффективный способ сделать это ? Изменить drawable во время выполнения ? или создать новый drawable во время выполнения в Java ?

второй вопрос: как это сделать ? Я попробовал оба способа (воссоздать этот drawable в коде java / изменить XML drawable во время выполнения) и не удалось : - (

любая помощь будет высоко оценили.

4 ответов


Так что это пользовательский Drawable вы можете использовать:

class LineDrawable extends Drawable {
    private Paint mPaint;

    public LineDrawable() {
        mPaint = new Paint();
        mPaint.setStrokeWidth(3);
    }

    @Override
    public void draw(Canvas canvas) {
        int lvl = getLevel();
        Rect b = getBounds();
        float x = b.width() * lvl / 10000.0f;
        float y = (b.height() - mPaint.getStrokeWidth()) / 2;
        mPaint.setColor(0xffff0000);
        canvas.drawLine(0, y, x, y, mPaint);
        mPaint.setColor(0xff00ff00);
        canvas.drawLine(x, y, b.width(), y, mPaint);
    }

    @Override
    protected boolean onLevelChange(int level) {
        invalidateSelf();
        return true;
    }

    @Override
    public void setAlpha(int alpha) {
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}

и тестовый код:

View v = new View(this);
final LineDrawable d = new LineDrawable();
d.setLevel(4000);
v.setBackgroundDrawable(d);
setContentView(v);
OnTouchListener l = new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int lvl = (int) (10000 * event.getX() / v.getWidth());
        d.setLevel(lvl);
        return true;
    }
};
v.setOnTouchListener(l);

как использовать прогресс бар? Стиль маркеров done и to-do можно установить программно или с помощью xml-файлов. Ваш код будет более читабельным/ремонтопригодным, потому что вы будете использовать правильный виджет для работы. Ваш макет будет содержать:

<ProgressBar
    android:id="@+id/progressBar"
    android:layout_height="3dip"
    android:layout_width="match_parent"
    android:progressDrawable="@drawable/progress_bar" />

вы можете обновить строку из кода, используя например:

ProgressBar bar = (ProgressBar)findViewById(R.id.progressBar);
bar.setProgress(40);

этот пример переопределяет стиль бара (как указано атрибутом progressDrawable), используя res/drawable/progress_bar.XML файл - содержание ниже. У этого есть дополнительная приятность, такая как градиентное затенение и закругленные углы; отрегулируйте, как вы считаете нужным:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
  <item android:id="@android:id/background">
    <shape>
      <corners android:radius="5dip" />
      <gradient
        android:angle="270"
        android:centerColor="#ff5a5d5a"
        android:centerY="0.5"
        android:endColor="#ff747674"
        android:startColor="#ff9d9e9d" />
    </shape>
  </item>
  <item android:id="@android:id/progress">
    <clip>
      <shape>
        <corners android:radius="5dip" />
          <gradient
            android:angle="0"
            android:endColor="#ff009900"
            android:startColor="#ff000099" />
      </shape>
    </clip>
  </item>
</layer-list>

кредит http://www.tiemenschut.com/how-to-customize-android-progress-bars/, что дает гораздо больше информации о том, как настроить индикаторы прогресса.


Я нашел способ сделать это. Не знаю, самый ли это эффективный способ, но вот он:

я использовал RelativeLayout для суперпозиции изображений с цветом фона.

в макете.XML-код:

<RelativeLayout style="@style/CompletionBar">

<ImageView
    android:id="@+id/row_completion_bar_0"
    style="@style/CompletionBar0" />

<ImageView
    android:id="@+id/row_completion_bar_1"
    style="@style/CompletionBar1" />       

</RelativeLayout>

в стилях.XML-код:

<!-- Completion Bar (Relative Layout) -->
<style name="CompletionBar">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
</style>

<!-- Completion Bar 0 (ImageView) -->
<style name="CompletionBar0">
    <item name="android:layout_width">100dp</item>
    <item name="android:layout_height">2dp</item>
    <item name="android:background">#CCCCCC</item>
</style>

<!-- Completion Bar 1 (ImageView) -->
<style name="CompletionBar1">
    <item name="android:layout_width">40dp</item>
    <item name="android:layout_height">2dp</item>
    <item name="android:background">#555555</item>
</style>

в файле java:

ImageView cb1 = (ImageView)row.findViewById(R.id.row_completion_bar_1);
cb1.getLayoutParams().width = 40; /* Value in pixels, must convert to dp */

этот фрагмент будет работать для всех api

используйте этот:

Drawable drawable = editText.getBackground();
drawable.setColorFilter(editTextColor, PorterDuff.Mode.SRC_ATOP);
if(Build.VERSION.SDK_INT > 16) {
    editText.setBackground(drawable);
}else{
    editText.setBackgroundDrawable(drawable);
}