Заполняя круг постепенно снизу вверх андроид
Я создал круг с обводкой и белым фоном, используя xml. Как это можно заполнить постепенно снизу вверх при действиях пользователя (например, при последовательном нажатии кнопки)?
Есть ли бесплатная библиотека, которая может быть использована для достижения аналогичной цели?
1 ответ
Я создал класс Custom View, который будет делать то, что вы хотите. Существует четыре пользовательских атрибута, которые могут быть установлены в вашем макете XML:
fillColor
, color - Устанавливает цвет области заливки. По умолчаниюColor.WHITE
,strokeColor
, color - Устанавливает цвет ограничивающего круга. По умолчаниюColor.BLACK
,strokeWidth
, float - Устанавливает толщину ограничивающего круга. По умолчанию1.0
,value
, целое число: 0-100 - Устанавливает значение для области заполнения. По умолчанию0
,
Обратите внимание, что эти атрибуты должны иметь custom
префикс вместо android
префикс в вашем макете XML. Корень View
также должен содержать custom
пространство имен XML. (См. Пример ниже.) Другой стандарт View
атрибуты - такие как layout_width
, background
и т. д. - есть в наличии.
Во-первых, 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) {}
}
);
}
}
И скриншот демо-приложения: