Pertanyaan mengisi lingkaran secara bertahap dari bawah ke atas android


Saya telah membuat lingkaran dengan stroke dan latar belakang putih menggunakan xml. Bagaimana ini dapat diisi secara bertahap dari bawah ke atas pada tindakan pengguna (misalnya pada penekanan tombol yang berurutan)?enter image description here

Apakah ada perpustakaan gratis yang dapat digunakan untuk mencapai hal serupa?


21
2017-07-21 06:00


asal


Jawaban:


Saya membuat kelas Tampilan Khusus yang akan melakukan apa yang Anda inginkan. Ada empat atribut khusus yang dapat diatur dalam xml tata letak Anda:

  • fillColor, warna - Mengatur warna area isian. Default-nya Color.WHITE.
  • strokeColor, warna - Menetapkan warna lingkaran pembatas. Default-nya Color.BLACK.
  • strokeWidth, mengapung - Menetapkan ketebalan lingkaran pembatas. Default-nya 1.0.
  • value, bilangan bulat: 0-100 - Menetapkan nilai untuk area isian. Default-nya 0.

Harap perhatikan bahwa atribut ini harus memiliki custom awalan sebagai pengganti dari android awalan di xml tata letak Anda. Akar View juga harus mengandung custom xml namespace. (Lihat contoh di bawah.) Standar lainnya View atribut - seperti layout_width, background, dll. - tersedia.

Pertama, itu CircleFillView kelas:

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);
    }
}

Sekarang, agar atribut xml khusus berfungsi, Anda harus meletakkan file berikut di /res/values folder proyek Anda.

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>

Berikut ini adalah file untuk aplikasi demonstrasi sederhana, di mana CircleFillViewNilai dikendalikan dengan SeekBar.

File tata letak untuk kami 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>

Dan, itu MainActivity kelas:

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) {}
            }
        );
    }   
}

Dan tangkapan layar dari aplikasi demo:

screenshot


47
2017-07-21 13:45