Android 사용자 정의 View 의 원형 진행 막대 단추

소개 하 다.
오늘 출근 할 때 어떤 친구 가 나 에 게 버튼 식 진 도 를 어떻게 실현 하 느 냐 고 물 었 다.먼저 그 가 실현 해 야 할 효과 도 를 살 펴 보 자.
这里写图片描述
일반적인 원형 진도 와 유사 하지만 중간 부분 에 두 개의 상태 가 있 는데 시작 하지 않 았 고 정지 상 태 를 나타 낸다.그리고 그 는 원형 진도 의 기능 이 이미 실현 되 었 다 고 말 했다.그럼 우 리 는 중간의 두 상태 만 처리 하면 된다.
먼저 실현 효과 도 를 살 펴 보 자.
这里写图片描述
위 에서 말 했 듯 이 우 리 는 중간 상태의 변화 만 처리 하면 된다.진도 에 대한 처 리 는 홍 양 글 에서 이 루어 졌 다.
http://blog.csdn.net/lmj623565791/article/details/43371299
구체 적 인 실현 을 시작 하 겠 습 니 다.
구체 적 실현
사용자 정의 실현 은 공식 적 으로 제공 하 는 절차 에 따라 이 루어 집 니 다.사용자 정의 View 절차 전에 저도 글 을 한 편 썼 습 니 다.관심 이 있 는 친 구 는 Android 사용자 정의 View 의 공식 적 인 방법 을 볼 수 있 습 니 다.
전체 설명 을 위해 서 는 원형 진도 조 의 사용자 정의 가 언급 되 어 있 으 며,진도 의 실현 이 일부 절 차 를 직접 뛰 어 넘 을 수 있다 는 것 을 알 고 있 습 니 다.
1.보기 만 들 기
실현 할 외곽 진 도 를 관찰 하려 면 두 가지 진도 가 있 습 니 다.하 나 는 기본 적 인 원형 을 나타 내 고 다른 하 나 는 진 도 를 나타 내 는 색 입 니 다.그래서 여 기 는 두 개의 진도 항목 의 색상 너비 와 높 은 정의 와 관련된다.원 을 그 리 려 면 반경 이 필요 할 거 야.
view 를 만 드 는 데 세 단계 가 있 습 니 다.
(1)속성 정의

<declare-styleable name="ButtonCircleProgressBar">
<!--       -->
<attr name="progress_unreached_color" format="color" />
<!--    -->
<attr name="progress_reached_color" format="color" />
<!--     -->
<attr name="progress_reached_bar_height" format="dimension" />
<!--        -->
<attr name="progress_unreached_bar_height" format="dimension" />
<!--    -->
<attr name="radius" format="dimension" />
</declare-styleable>
(1)속성 변수 정의 및 구조 방법 에서 속성 획득

private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
/**
* The status of this view currently;
*/
private Status mStatus = Status.End;
/**
* painter of all drawing things
*/
protected Paint mPaint = new Paint();
/**
* height of reached progress bar
*/
protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/**
* color of reached bar
*/
protected int mReachedBarColor = DEFAULT_TEXT_COLOR;
/**
* color of unreached bar
*/
protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;
/**
* height of unreached progress bar
*/
protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/**
* the length of triangle
*/
private int triangleLength;
/**
* use path to draw triangle
*/
private Path mPath;
/**
* mRadius of view
*/
private int mRadius = dp2px(30);
public ButtonCircleProgressBar(Context context) {
this(context,null);
}
public ButtonCircleProgressBar(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ButtonCircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// init values from custom attributes
final TypedArray attributes = getContext().obtainStyledAttributes(
attrs, R.styleable.ButtonCircleProgressBar);
mReachedBarColor = attributes
.getColor(
R.styleable.ButtonCircleProgressBar_progress_reached_color,
Color.BLUE);
mUnReachedBarColor = attributes
.getColor(
R.styleable.ButtonCircleProgressBar_progress_unreached_color,
DEFAULT_COLOR_UNREACHED_COLOR);
mReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.ButtonCircleProgressBar_progress_reached_bar_height,
mReachedProgressBarHeight);
mUnReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.ButtonCircleProgressBar_progress_unreached_bar_height,
mUnReachedProgressBarHeight);
mRadius = (int) attributes.getDimension(
R.styleable.ButtonCircleProgressBar_radius, mRadius);
triangleLength = mRadius;
attributes.recycle();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPath = new Path();//need path to draw triangle
}
public Status getStatus() {
return mStatus;
}
public void setStatus(Status status) {
mStatus = status;
invalidate();
}
public enum Status{
End,
Starting
}
기본 속성 을 가 져 옵 니 다.여기 서 mStatus 는 현재 View 의 상 태 를 표시 합 니 다.End 코드 가 끝 났 고 Starting 이 진행 중 입 니 다.우 리 는 이 두 가지 상태 로 어떻게 draw 를 해서 적당 한 효 과 를 낼 수 있 는 지 를 판정한다.setStatus 를 제공 하여 Staus 에 상 태 를 설정 합 니 다.
mPath 는 시작 하지 않 은 삼각형 을 그립 니 다.
2.View 의 레이아웃 처리
이 단 계 는 주로 onMeasure 방법 에서 적당 한 너비 와 높이 를 측정 하 는 것 이다.

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int paintWidth = Math.max(mReachedProgressBarHeight,
mUnReachedProgressBarHeight);
if (heightMode != MeasureSpec.EXACTLY) {
int exceptHeight = (int) (getPaddingTop() + getPaddingBottom()
+ mRadius * 2 + paintWidth);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(exceptHeight,
MeasureSpec.EXACTLY);
}
if (widthMode != MeasureSpec.EXACTLY) {
int exceptWidth = (int) (getPaddingLeft() + getPaddingRight()
+ mRadius * 2 + paintWidth);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(exceptWidth,
MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
너비 와 높이 가 정확하게 지정 되 지 않 은 경우 만 처리 하고 padding 에 전체 원 과 Paint 의 폭 을 더 해 구체 적 인 값 을 계산 합 니 다.
다음은 세 번 째 단계 입 니 다.효 과 를 그립 니 다.
3.보기 그리 기
좀 더 뚜렷 해 지기 위해 서 는 원 을 그 리 는 진 도 를 먼저 말 하고 원 중간 상 태 를 말한다.
(1)원 그리 기

@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(getPaddingLeft(), getPaddingTop());
mPaint.setStyle(Paint.Style.STROKE);
// draw unreaded bar
mPaint.setColor(mUnReachedBarColor);
mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
// draw reached bar
mPaint.setColor(mReachedBarColor);
mPaint.setStrokeWidth(mReachedProgressBarHeight);
float sweepAngle = getProgress() * 1.0f / getMax() * 360;
canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2), 0,
sweepAngle, false, mPaint);
canvas.draw Circle(mRadius,mRadius,mRadius,mPaint)을 통 해기본 상태의 원 을 그립 니 다.이후 붓 의 색깔 을 바 꿔 진도 에 따라 원 호 를 그립 니 다.
(2)가운데 상 태 를 그립 니 다.
첫 번 째 는 시작 되 지 않 은 상황 이 고 중간 은 삼각형 이다.우 리 는 Path 를 사용 하여 삼각형 을 그립 니 다.주로 moveto(float x,float y)를 통 해 첫 번 째 점 을 설정 한 다음 에 lineto(float x,float y)를 통 해 삼각형 을 연결 합 니 다.Paint 를 채 우기 위해 설정 합 니 다.
첫 번 째 점 은 삼각형 의 왼쪽 상단 의 정점 으로 설정 합 니 다.
그럼 첫 번 째 점 은 어떻게 계산 해요?
우 리 는 여기에서 등변 삼각형 을 그 려 서 변 의 길 이 를 반경 과 같이 설정 합 니 다.
첫 번 째 점 의 x 좌 표 는 원 의 지름 에서 삼각형 의 높이 를 뺀 다음 에 2 로 나 누 어야 한다.즉,:

float leftX = (float) ((2*mRadius-Math.sqrt(3.0)/2*triangleLength)/2); 
y 좌 표 는:mRadius-(triangleLength/2)
두 번 째 점 은 삼각형 의 왼쪽 아래 를 선택 하 십시오.x 좌 표 는 변 하지 않 습 니 다.y 값 은 반지름 에 변 의 절반 을 더 합 니 다.mRadius+(triangleLength/2)
세 번 째 점 에서 오른쪽 점 을 선택 하면 x 점 의 좌 표 는 첫 번 째 점 의 x 좌표 에 삼각형 의 높이 를 더 한 것 이 분명 하 다.
즉,(float)(leftX+Math.sqrt(3.0)/2*triangleLength),y 점 좌 표 는 반경 mRadius 입 니 다.
마지막 으로 첫 번 째 점 으로 돌아 가면 삼각형 으로 연결된다.
mPath 설정 의 전체 코드 는 다음 과 같 습 니 다.

public class ButtonCircleProgressBar extends ProgressBar {
.........
mPath = new Path();//need path to draw triangle
triangleLength = mRadius;
float leftX = (float) ((2*mRadius-Math.sqrt(3.0)/2*triangleLength)/2);
float realX = (float) (leftX+leftX*0.2);
mPath.moveTo(realX,mRadius-(triangleLength/2));
mPath.lineTo(realX,mRadius+(triangleLength/2));
mPath.lineTo((float) (realX+Math.sqrt(3.0)/2*triangleLength),mRadius);
mPath.lineTo(realX,mRadius-(triangleLength/2));
}
여기에 realX 를 사용 하여 leftX 의 두 배로 설정 한 것 은 삼각형 이 중간 에 설 치 된 효과 가 좋 지 않다 고 느 꼈 기 때문에 그 에 게 원래 의 기초 위 에서 0.2 배의 거 리 를 증가 시 켰 다.
mPath 변수 가 있 으 면 onDraw 에서 시작 되 지 않 은 상태의 삼각형 을 그 릴 수 있 습 니 다.코드 를 보 세 요.

@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(getPaddingLeft(), getPaddingTop());
....
if (mStatus==Status.End){//     ,    
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPath(mPath,mPaint);//  drawPath
}else{
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(dp2px(5));
canvas.drawLine(mRadius*2/3,mRadius*2/3,mRadius*2/3,2*mRadius*2/3,mPaint);
canvas.drawLine(2*mRadius-(mRadius*2/3),mRadius*2/3,2*mRadius-(mRadius*2/3),2*mRadius*2/3,mPaint);
}
canvas.restore();
}
진행 중인 상 태 는 두 개의 선 을 그 리 는 것 이다.첫 번 째 선 x 는 반지름 의 2/3 배,시작 y 점 은 2/3 배,끝 은 시작 y 점 의 2/3 배 이다.
다른 선과 x 점 직경 에서 mRadius*2/3 을 빼 면 y 점 좌표 의 변 화 는 이전 선과 같다.
이렇게 해서 온 드 로 방법 이 완성 되 었 습 니 다.
4.사용자 상호작용 처리
업데이트 진 도 를 다운로드 하 는 경우 이 컨트롤 은 상태 표시 만 하기 때문에 이 단 계 는 필요 없습니다.사용 하려 면 클릭 이 벤트 를 스스로 설정 하면 됩 니 다.
쓰다

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.qiangyu.test.buttoncircleprogress.MainActivity">
<com.qiangyu.test.buttoncircleprogress.view.ButtonCircleProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dip"
android:padding="5dp"
android:progress="30" />
</RelativeLayout>
Activity 에 서 는 클릭 이벤트 수정 상 태 를 설정 하고 구체 적 으로 자신의 논리 에 따라 처리 합 니 다.

public class MainActivity extends AppCompatActivity {
private ButtonCircleProgressBar mProgressBar;
private static final int MSG_PROGRESS_UPDATE = 0x110;
private int progress;
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
progress = mProgressBar.getProgress();
mProgressBar.setProgress(++progress);
if (progress >= 100) {
mHandler.removeMessages(MSG_PROGRESS_UPDATE);
progress = 0;
mProgressBar.setStatus(ButtonCircleProgressBar.Status.End);
mProgressBar.setProgress(0);
}else{
mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE, 100);
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressBar = (ButtonCircleProgressBar) findViewById(R.id.progressBar);
mProgressBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mProgressBar.getStatus()== ButtonCircleProgressBar.Status.Starting){
mProgressBar.setStatus(ButtonCircleProgressBar.Status.End);
mHandler.removeMessages(MSG_PROGRESS_UPDATE);
}else{
mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE);
mProgressBar.setStatus(ButtonCircleProgressBar.Status.Starting);
}
}
});
}
}
자,여기까지 원형 진도 스 트 립 버튼 이 이 루어 졌 습 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 메 시 지 를 남 겨 주세요.편집장 님 께 서 바로 답 해 주 실 겁 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기