android - 从下到上逐渐填充一个圆圈android

标签 android android-layout android-view android-shape

我使用 xml 创建了一个带有笔触和白色背景的圆圈。如何在用户操作上从下到上逐渐填充(例如在连续按下按钮时)? enter image description here

有没有免费的库可以用来实现类似的东西?

最佳答案

我创建了一个自定义 View 类,它会做你想做的事。您可以在布局 xml 中设置四个自定义属性:

  • fillColor, color - 设置填充区域的颜色。默认为 Color.WHITE
  • strokeColor, color - 设置边界圆的颜色。默认为 Color.BLACK
  • strokeWidth, float - 设置边界圆的粗细。默认为 1.0
  • value, integer: 0-100 - 设置填充区域的值。默认为 0

请注意,这些属性必须具有 custom 前缀,而不是布局 xml 中的 android 前缀。根 View 还应包含 custom xml 命名空间。 (参见下面的示例。) 其他标准 View 属性 - 例如 layout_widthbackground 等 -可用。

一、CircleFillView类:

public class CircleFillView extends View
{
    public static final int MIN_VALUE = 0;
    public static final int MAX_VALUE = 100;

    private PointF center = new PointF();
    private RectF circleRect = new RectF();
    private Path segment = new Path();  
    private Paint strokePaint = new Paint();
    private Paint fillPaint = new Paint();

    private int radius;

    private int fillColor;
    private int strokeColor;
    private float strokeWidth;
    private int value;

    public CircleFillView(Context context)
    {
        this(context, null);
    }

    public CircleFillView(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        TypedArray a = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.CircleFillView,
            0, 0);

        try
        {
            fillColor = a.getColor(R.styleable.CircleFillView_fillColor, Color.WHITE);
            strokeColor = a.getColor(R.styleable.CircleFillView_strokeColor, Color.BLACK);
            strokeWidth = a.getFloat(R.styleable.CircleFillView_strokeWidth, 1f);
            value = a.getInteger(R.styleable.CircleFillView_value, 0);
            adjustValue(value);
        }
        finally
        {
            a.recycle();
        }   

        fillPaint.setColor(fillColor);
        strokePaint.setColor(strokeColor);
        strokePaint.setStrokeWidth(strokeWidth);
        strokePaint.setStyle(Paint.Style.STROKE);
    }

    public void setFillColor(int fillColor)
    {
        this.fillColor = fillColor;
        fillPaint.setColor(fillColor);
        invalidate();
    }

    public int getFillColor()
    {
        return fillColor;
    }

    public void setStrokeColor(int strokeColor)
    {
        this.strokeColor = strokeColor;
        strokePaint.setColor(strokeColor);
        invalidate();
    }

    public int getStrokeColor()
    {
        return strokeColor;
    }

    public void setStrokeWidth(float strokeWidth)
    {
        this.strokeWidth = strokeWidth;
        strokePaint.setStrokeWidth(strokeWidth);
        invalidate();
    }

    public float getStrokeWidth()
    {
        return strokeWidth;
    }

    public void setValue(int value)
    {
        adjustValue(value);
        setPaths();

        invalidate();
    }

    public int getValue()
    {
        return value;
    }

    private void adjustValue(int value)
    {
        this.value = Math.min(MAX_VALUE, Math.max(MIN_VALUE, value));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);

        center.x = getWidth() / 2;
        center.y = getHeight() / 2;
        radius = Math.min(getWidth(), getHeight()) / 2 - (int) strokeWidth;
        circleRect.set(center.x - radius, center.y - radius, center.x + radius, center.y + radius);

        setPaths();
    }

    private void setPaths()
    {
        float y = center.y + radius - (2 * radius * value / 100 - 1);
        float x = center.x - (float) Math.sqrt(Math.pow(radius, 2) - Math.pow(y - center.y, 2));

        float angle = (float) Math.toDegrees(Math.atan((center.y - y) / (x - center.x)));
        float startAngle = 180 - angle;
        float sweepAngle = 2 * angle - 180;

        segment.rewind();
        segment.addArc(circleRect, startAngle, sweepAngle);
        segment.close();
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);

        canvas.drawPath(segment, fillPaint);
        canvas.drawCircle(center.x, center.y, radius, strokePaint);
    }
}

现在,要使自定义 xml 属性生效,您需要将以下文件放入项目的 /res/values 文件夹中。

attrs.xml:

<resources>
    <declare-styleable name="CircleFillView" >
        <attr name="fillColor" format="color" />
        <attr name="strokeColor" format="color" />
        <attr name="strokeWidth" format="float" />
        <attr name="value" format="integer" />
    </declare-styleable>
</resources>

以下是一个简单演示应用程序的文件,其中 CircleFillView 的值由 SeekBar 控制。

我们的Activity的布局文件,main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res/com.example.circlefill"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical" >

    <com.example.circlefill.CircleFillView
        android:id="@+id/circleFillView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#ffffff"
        custom:fillColor="#6bcae2"
        custom:strokeColor="#75b0d0"
        custom:strokeWidth="20"
        custom:value="65" />

    <SeekBar android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

还有,MainActivity 类:

public class MainActivity extends Activity
{
    CircleFillView circleFill;
    SeekBar seekBar;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        circleFill = (CircleFillView) findViewById(R.id.circleFillView);

        seekBar = (SeekBar) findViewById(R.id.seekBar);
        seekBar.setProgress(circleFill.getValue());
        seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
            {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
                {
                    if (fromUser)
                        circleFill.setValue(progress);
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {}

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {}
            }
        );
    }   
}

以及演示应用的截图:

screenshot

关于android - 从下到上逐渐填充一个圆圈android,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24858531/

相关文章:

android - 检测android中的应用程序崩溃

android - animateLayoutChanges 不适用于嵌套布局?

java - 如何在 android 的 ListView 中获取项目的 View ?

java - 如何使用Android在线播放音乐?

android - 具有自定义背景和 "?attr/selectableItemBackground"的按钮

java - 如何在 Firebase 实时数据库中存储用户的提供商帐户?

android - 在 android.arch.navigation :navigation-ui-ktx 中找不到新的 <dialog> 标签

android - Ionic v2 Google Maps API Android Build Error : cannot access AbstractSafeParcelable options. compassEnabled(controls.getBoolean ("compass"));

android - 覆盖android seekbar样式

android - 在 android 中创建可绘制和可缩放的 ImageView