如何以编程方式创建或更改由不同颜色的线条组成的可绘制对象

8

我需要绘制一条三维线来表示一个问答游戏中的水平完成情况。

这条线必须由两种颜色组成。例如,如果用户完成了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%的比例。

第一个问题:最有效的方法是什么?在运行时更改可绘制对象还是在Java中创建新的可绘制对象?

第二个问题:如何实现?我尝试了两种方法(在Java代码中重新创建该可绘制对象/在运行时更改XML可绘制对象),但没有成功。

非常感谢您的任何帮助。


我会像这样创建一个自定义的Drawable类,名为LineDrawable,继承自Drawable类 { .... - pskink
谢谢您的回答。您会如何确切地做到这一点? - Stéphane
只需覆盖所有Drawable的抽象方法,特别是draw(Canvas)。 - pskink
我终于找到了一种更简单的方法,使用ImageViews背景颜色和相对布局。我现在无法发布解决方案,因为在8小时内我没有足够的声望来回答自己的问题。我会尽快回答。 - Stéphane
4个回答

16

这是一个你可以使用的自定义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);

你有没有想法,哪种方法更有效率:这个还是我的ImageViews解决方案?非常感谢! - Stéphane

3

使用进度条怎么样?已完成和待完成标记的样式可以通过编程或者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);

以下示例使用res/drawable/progress_bar.xml文件覆盖了进度条的样式(根据progressDrawable属性指示),该文件的内容如下。这个进度条具有额外的美观效果,如渐变阴影和圆角,可以根据您的需要进行调整:

<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/提供的更详细定制Android进度条的方法。


0
这段代码适用于所有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);
}

0
我找到了一种方法来实现这个。不知道是否是最有效的方法,但是这里是:
我使用RelativeLayout来叠加带有背景颜色的ImageView。
在layout.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>

在styles.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 */

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接