Android 사용자 정의 컨트롤 의 원형 진행 막대 애니메이션
먼저 그림 을 붙 입 니 다.
어,괜 찮 은 것 같 지?그냥 진도 표 색깔 이 좀 못 생 겼 어.그런데 우 리 는 프로그래머 야.미 공 이 아니 야.배색 이라는 문 제 는 당연히 고려 범위 안에 있 지 않 아.
이러한 사용자 정의 컨트롤 을 어떻게 쓰 느 냐 에 중점 을 두 겠 습 니 다.
우선,채 워 지지 않 은 진도 로 회색 밑그림 이 필요 합 니 다.
그 다음 에 들 어 오 는 현재 진도 값 에 따라 채 울 때의 진도 원 호 를 그립 니 다.이 원호 에 대응 하 는 원심 각 은 현재 진도 와 진도 의 최대 치(보통 100)의 비례 로 계산 합 니 다.
그 다음 에 진도 값 에 따라 문자 알림 을 그립 니 다.
마지막 으로 컨트롤 을 다시 그리고 애니메이션 을 추가 하여 진 도 를 표시 하 는 효 과 를 얻 을 수 있 습 니 다.
코드 는 다음 과 같 습 니 다:
1、attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="circleProgressBar">
<attr name="circleWidth" format="dimension" />
<attr name="betaAngle" format="integer" />
<attr name="firstColor" format="color" />
<attr name="secondColor" format="color" />
</declare-styleable>
</resources>
2、CircleProgressBar.java
package com.ctgu.circleprogressbar;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.OvershootInterpolator;
public class CircleProgressBar extends View
{
/**
* , 100
*/
private int maxValue = 100;
/**
*
*/
private int currentValue = 0;
/**
* , ,alphaAngle=(currentValue/maxValue)*360
*/
private float alphaAngle;
/**
* , Color.LTGRAY
*/
private int firstColor;
/**
*
*/
private int secondColor;
/**
*
*/
private int circleWidth;
/**
*
*/
private Paint circlePaint;
/**
*
*/
private Paint textPaint;
/**
*
*/
private int[] colorArray = new int[] { Color.parseColor("#27B197"), Color.parseColor("#00A6D5") };//
/**
*
*
* @param context
*/
public CircleProgressBar(Context context)
{
this(context, null);
}
/**
* xml view , 。 。
*
* @param context
*
* @param attrs
*
*/
public CircleProgressBar(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
/**
* xml 。 , theme , style 。
* : defStyle - The default style to apply to this view. If 0,
* no style will be applied (beyond what is included in the theme). This may
* either be an attribute resource, whose value will be retrieved from the
* current theme, or an explicit style resource.
* view 。 0,
* ( )。 , , 。
*
* @param context
*
* @param attrs
*
* @param defStyleAttr
*
*/
public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.circleProgressBar,
defStyleAttr, 0);
int n = ta.getIndexCount();
for (int i = 0; i < n; i++)
{
int attr = ta.getIndex(i);
switch (attr)
{
case R.styleable.circleProgressBar_firstColor:
firstColor = ta.getColor(attr, Color.LTGRAY); //
break;
case R.styleable.circleProgressBar_secondColor:
secondColor = ta.getColor(attr, Color.BLUE); //
break;
case R.styleable.circleProgressBar_circleWidth:
circleWidth = ta.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 6, getResources().getDisplayMetrics())); // 6dp
break;
default:
break;
}
}
ta.recycle();
circlePaint = new Paint();
circlePaint.setAntiAlias(true); //
circlePaint.setDither(true); //
circlePaint.setStrokeWidth(circleWidth);
textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setDither(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{// ,
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(Math.min(measureWidth, measureHeight), Math.min(measureWidth, measureHeight));
}
@Override
protected void onDraw(Canvas canvas)
{
int center = this.getWidth() / 2;
int radius = center - circleWidth / 2;
drawCircle(canvas, center, radius); //
drawText(canvas, center, radius);
}
/**
*
*
* @param canvas
*
* @param center
* x y
* @param radius
*
*/
private void drawCircle(Canvas canvas, int center, int radius)
{
circlePaint.setShader(null); // shader
circlePaint.setColor(firstColor); // ,
circlePaint.setStyle(Paint.Style.STROKE); //
canvas.drawCircle(center, center, radius, circlePaint); //
RectF oval = new RectF(center - radius, center - radius, center + radius, center + radius); //
//
// shader Android 。Shader , 。
LinearGradient linearGradient = new LinearGradient(circleWidth, circleWidth, getMeasuredWidth()
- circleWidth, getMeasuredHeight() - circleWidth, colorArray, null, Shader.TileMode.MIRROR);
circlePaint.setShader(linearGradient);
circlePaint.setShadowLayer(10, 10, 10, Color.RED);
circlePaint.setColor(secondColor); //
circlePaint.setStrokeCap(Paint.Cap.ROUND); //
alphaAngle = currentValue * 360.0f / maxValue * 1.0f; // , float , alphaAngle 0
canvas.drawArc(oval, -90, alphaAngle, false, circlePaint);
}
/**
*
*
* @param canvas
*
* @param center
* x y
* @param radius
*
*/
private void drawText(Canvas canvas, int center, int radius)
{
float result = (currentValue * 100.0f / maxValue * 1.0f); //
String percent = String.format("%.1f", result) + "%";
textPaint.setTextAlign(Paint.Align.CENTER); // , x
textPaint.setColor(Color.BLACK); //
textPaint.setTextSize(40); //
textPaint.setStrokeWidth(0); // 0,
Rect bounds = new Rect(); //
textPaint.getTextBounds(percent, 0, percent.length(), bounds); //
FontMetricsInt fontMetrics = textPaint.getFontMetricsInt(); // Text
int baseline = center + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom; // , http://blog.csdn.net/harvic880925/article/details/50423762
canvas.drawText(percent, center, baseline, textPaint); //
}
/**
*
*
* @param width
*/
public void setCircleWidth(int width)
{
this.circleWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, getResources()
.getDisplayMetrics());
circlePaint.setStrokeWidth(circleWidth);
invalidate();
}
/**
* , LTGRAY
*
* @param color
*/
public void setFirstColor(int color)
{
this.firstColor = color;
circlePaint.setColor(firstColor);
invalidate();
}
/**
* , <br>
*
* @param color
*/
public void setSecondColor(int color)
{
this.secondColor = color;
circlePaint.setColor(secondColor);
invalidate();
}
/**
*
*
* @param colors
* , int[]
*/
public void setColorArray(int[] colors)
{
this.colorArray = colors;
invalidate();
}
/**
*
*
* @param progress
* , 0 100
*/
public void setProgress(int progress)
{
int percent = progress * maxValue / 100;
if (percent < 0)
{
percent = 0;
}
if (percent > 100)
{
percent = 100;
}
this.currentValue = percent;
invalidate();
}
/**
* ,
*
* @param progress
* , 0 100
* @param useAnimation
* ,true
*/
public void setProgress(int progress, boolean useAnimation)
{
int percent = progress * maxValue / 100;
if (percent < 0)
{
percent = 0;
}
if (percent > 100)
{
percent = 100;
}
if (useAnimation) //
{
ValueAnimator animator = ValueAnimator.ofInt(0, percent);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
currentValue = (int) animation.getAnimatedValue();
invalidate();
}
});
animator.setInterpolator(new OvershootInterpolator());
animator.setDuration(1000);
animator.start();
}
else
{
setProgress(progress);
}
}
}
3、activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:lh2="http://schemas.android.com/apk/res/com.ctgu.circleprogressbar"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.ctgu.circleprogressbar.CircleProgressBar
android:id="@+id/circleProgressBar"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
android:layout_gravity="center"
android:layout_marginTop="20dp"
lh2:circleWidth="6dp"
lh2:firstColor="#d3d3d3"
lh2:secondColor="#3B95C8" />
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="#778899" />
</RelativeLayout>
4、MainActivity.java
package com.ctgu.circleprogressbar;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.widget.SeekBar;
public class MainActivity extends Activity
{
private CircleProgressBar circleProgressBar; //
private SeekBar seekbar; //
private int[] colors = new int[] { Color.parseColor("#27B197"), Color.parseColor("#00A6D5") };
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
circleProgressBar = (CircleProgressBar) findViewById(R.id.circleProgressBar);
// circleProgressBar.setFirstColor(Color.LTGRAY);
// circleProgressBar.setColorArray(colors); // , 。
// circleProgressBar.setCircleWidth(6);
seekbar = (SeekBar) findViewById(R.id.seekbar);
seekbar.setMax(100);
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
if (fromUser)
{
// circleProgressBar.setProgress(progress); //
circleProgressBar.setProgress(progress, true); //
}
}
});
}
}
코드 설명 이 상세 해서 기본적으로 사용자 정의 컨트롤 을 알 아 보 는 사람 은 모두 알 아 볼 수 있 습 니 다.이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.