Android 사용자 정의 View 모방 텐 센트 TIM 드 롭 다운 새로 고침 View
17275 단어 android드 롭 다운 리 셋view
사용자 정의 뷰 는 안 드 로 이 드 개발 의 한 대학 질문 입 니 다.우연히 TIM 메 일 박스 인터페이스의 새로 고침 View 가 재 미 있 는 것 을 보 았 습 니 다.그래서 스스로 하 나 를 실 현 했 습 니 다.먼저 TIM 안의 효과 도 를 보 세 요.
2 수요 분석
위의 동 도 를 보면 우리 가 실현 해 야 할 기능 도 알 수 있다.
4.567917.끌 리 는 진도 에 따라 작은 공의 위 치 를 이동한다.4.567918.
4
새로 만 든 Refreshview 클래스 는 View 에서 계승 한 다음 에 Refreshview 에서 내부 실체 클래스 를 새로 만 듭 니 다:Circle
Circle 코드 를 볼 게 요.
#Cirlce.java
class Circle {
int x;
int y;
int r;
int color;
public Circle(int x, int y, int r, int color) {
this.x = x;
this.y = y;
this.r = r;
this.color = color;
}
}
이것 은 실체 류 로 그 안에 x,y,r,color 속성 을 제공 하여 각각 원심 좌표 의 x 값,y 값,원 의 반지름 r 와 색 을 대표 합 니 다.이 를 통 해 작은 원구 의 관련 속성 을 저장 합 니 다.
다음은 우리 가 평소에 사용자 정의 View 를 자주 다시 쓰 는 세 가지 방법 입 니 다.먼저 onMeasure()를 보 세 요.
#RefreshView.java
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.EXACTLY) {
setMeasuredDimension(mWidth, heightSize);
} else if (widthMeasureSpec == MeasureSpec.EXACTLY && heightMeasureSpec == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSize, mHeight);
} else if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
setMeasuredDimension(widthSize, heightSize);
} else {
setMeasuredDimension(mWidth, mHeight);
}
}
레이아웃 파일 에 적합 한 wrapcontent 매개 변 수 는 이 방법 을 다시 써 야 합 니 다.이어서 onLayout()방법 을 보십시오.
#RefreshView.java
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
initContentAttr(getMeasuredWidth(), getMeasuredHeight());
resetCircles();
}
이 방법 에 서 는 initContentAttr()방법 을 사용 하여 내용 크기 와 resetCircles()를 초기 화하 여 세 개의 작은 공의 속성 을 초기 화 합 니 다.이 두 가지 방법 을 각각 살 펴 보 자.#RefreshView.java
private void initContentAttr(int width, int height) {
mContentWidth = width - getPaddingLeft() - getPaddingRight();
mContentHeight = height - getPaddingTop() - getPaddingBottom();
}
이 방법 은 매우 간단 하 다.바로 padding 처 리 를 해서 진정한 레이아웃 크기 를 얻 는 것 이다.padding 을 처리 하지 않 으 면 사용자 가 padding 을 설정 하면 효력 을 잃 습 니 다.resetCircles()다시 보기:#RefreshView.java
public static final int STATE_ORIGIN = 0;
public static final int STATE_PREPARED = 1;
private int mOriginState = STATE_ORIGIN;
private void resetCircles() {
if (mCircles.isEmpty()) {
int x = mContentWidth / 2;
int y = mContentHeight / 2;
mGap = x - mMinRadius; //
Circle circleLeft = new Circle(x, y, mMinRadius, 0xffff7f0a);
Circle circleCenter = new Circle(x, y, mMaxRadius, Color.RED);
Circle circleRight = new Circle(x, y, mMinRadius, Color.GREEN);
mCircles.add(LEFT, circleLeft);
mCircles.add(RIGHT, circleRight);
mCircles.add(CENTER, circleCenter);
}
if (mOriginState == STATE_ORIGIN) {
int x = mContentWidth / 2;
int y = mContentHeight / 2;
for (int i = 0; i < mCircles.size(); i++) {
Circle circle = mCircles.get(i);
circle.x = x;
circle.y = y;
if (i == CENTER) {
circle.r = mMaxRadius;
} else {
circle.r = mMinRadius;
}
}
} else {
prepareToStart();
}
}
이 방법 은 작은 공 을 초기 화하 고 초기 화 하 는 데 사 용 됩 니 다.방법 에서 진행 되 는 두 개의 큰 if..else 문 구 는 작은 공 을 초기 화 해 야 하 는 지 판단 하 는 데 사 용 됩 니 다.두 번 째 문 구 는 작은 공의 초기 화 형 태 를 판단 하 는 데 사 용 됩 니 다.외부 에서 setOriginState()방법 을 사용 하여 작은 공의 초기 화 형 태 를 지정 할 수 있 습 니 다.지정 하지 않 으 면 기본적으로 NOMAL,즉 세 개의 공이 겹 치 는 것 입 니 다.#RefreshView.java
/**
*
* {@link #STATE_ORIGIN} ( ),
* {@link #STATE_PREPARED} ,
*/
public void setOriginState(int state) {
if (state == 0) {
mOriginState = STATE_ORIGIN;
} else {
mOriginState = STATE_PREPARED;
}
}
마지막 으로 가장 재 미 있 는 방법 인 onDraw()입 니 다.#RefreshView.java
@Override
protected void onDraw(Canvas canvas) {
for (Circle circle : mCircles) {
mPaint.setColor(circle.color);
canvas.drawCircle(circle.x + getPaddingLeft(), circle.y + getPaddingTop(), circle.r, mPaint);
}
}
이 방법 은 간단 합 니 다.mCircles 목록 에 있 는 원 을 그 렸 을 뿐 입 니 다.세 가지 방법 을 다 말 했 지만 이것 은 단지 몇 개의 작은 둥 근 공 을 그 렸 을 뿐이다.우리 의 수요 분석 에서 의 수 요 는 아직 실현 되 지 않 았 다.위의 방법 은 View 의 기 초 를 닦 았 기 때문에 이것 을 실현 하 는 것 도 어렵 지 않다.다음은 여러분 이 기대 하 는 수요 가 이 루어 졌 습 니 다.
드래그 하 는 진도 에 따라 작은 공의 위 치 를 이동 합 니 다.
구현 코드 는 다음 과 같 습 니 다:
#RefreshView.java
public void drag(float fraction) {
if (mOriginState == STATE_PREPARED) {
return;
}
if (mAnimator != null && mAnimator.isRunning()) {
return;
}
if (fraction > 1) {
return;
}
mCircles.get(LEFT).x = (int) (mMinRadius + mGap * (1f - fraction));
mCircles.get(RIGHT).x = (int) (mContentWidth / 2 + mGap * fraction);
postInvalidate();
}
방법 안에서 세 번 의 판단 을 하고 초기 상태 가 STATE 이면PREPARED(세 개의 공이 가장 거리 가 멀 어서 더 이상 변동 할 필요 가 없다),애니메이션 이 진행 중이 거나 진도 가 1 보다 크 면 이동 하지 않 는 다.그리고 작은 공의 속성 을 수정 하고 다시 그립 니 다.작은 공 이동 과정의 애니메이션
이것 은 사용자 정의 View 의 가장 어 려 운 부분 입 니 다.수학의 작은 연산 이 필요 합 니 다.좀 번 거 롭 습 니 다.
우 리 는 먼저 애니메이션 을 실현 하 는 논 리 를 정리 하고 시작 하 는 gif 를 보면 알 수 있 을 것 이다.애니메이션 을 시작 할 때 왼쪽 의 작은 공 은 가장 왼쪽 에 있 고 중간 에 있 는 작은 공 은 중간 에 있 으 며 오른쪽 은 가장 오른쪽 에 있다.우 리 는 하나하나 작은 공 으로 분석 했다.
4.567917.왼쪽 작은 공:애니메이션 이 시 작 된 후에 왼쪽 의 작은 공 은 오른쪽으로 이동 하고 점점 커 졌 다.작은 공이 중심 점 까지 운동 할 때 까지 중심 점 을 지나 면 작은 공 은 계속 오른쪽으로 이동 하지만 점점 작 아 졌 다.종점 에 도착 하면 작은 공 은 사라 질 것 이다(사라 지 는 과정 은 먼저 축소 하고 다시 사라 지 는 것 이다).그 다음 에 왼쪽 에서 나 타 났 다(나타 나 는 과정 도 작은 것 에서 큰 것 으로 변화 하고 아래 는 같다).그리고 상술 한 과정 을 반복 한다4.567917.중간 공:중간의 작은 공 은 먼저 오른쪽으로 이동 하고 점점 줄 어 든 다음 에 사라 진 다음 에 왼쪽 에서 나타 나 고 마지막 에 중간 으로 이동 하 며 그 사이 에 점점 커진다.뒤 에는 상술 한 동작 이 반복 된다4.567917.오른쪽 작은 공:오른쪽 에 있 는 작은 공 은 먼저 사라 진 다음 에 왼쪽 에서 나타 나 고 그 다음 에 중간 으로 이동 하 며 그 사이 에 점점 커지 고 그 다음 에 중심 점 에서 말단 으로 이동 하 며 그 사이 에 점점 줄어든다작은 공의 이동 과정 을 정리 하 는 것 은 코드 의 실현 에 매우 도움 이 되 므 로 우 리 는 분석 할 수 있다.
1)작은 공 마다 좌표계 의 이동 특징 이 같다.
2)작은 공 마다 애니메이션 의 진도 이동 특징 이 다르다.
듣 기 에 좀 까다 로 운 것 같 습 니 다.우 리 는 사람의 말로 설명 하 겠 습 니 다.
1)각 작은 공 은 좌표계 의 이동 특징 에 대해 똑 같 습 니 다.왼쪽 의 작은 공 은 좌표 의 맨 왼쪽 에 먼저 나타 난 다음 에 오른쪽으로 이동 합 니 다.그러면 중간 과 오른쪽 작은 공 은 요?사실은 똑 같 습 니 다.그들 은 좌표 축 의 가장 왼쪽 에 있 을 때 먼저 나타 나 고 오른쪽으로 이동 합 니 다.어떤 작은 공 이 든 좌표 축 의 같은 점 에서 의 동작 과 형 태 는 일치 해 야 합 니 다.
2)모든 작은 공이 애니메이션 의 진도 에 대한 이동 특징 은 다르다.왼쪽 의 작은 공 은 애니메이션 이 시작 할 때 가장 왼쪽 에 있 고 중간 에 있 는 작은 공 은 중간 에 있 으 며 오른쪽 은 가장 오른쪽 에 있다.애니메이션 이 시 작 된 후에 예 를 들 어 반 쯤 진행 되 었 을 때 왼쪽 의 작은 공 은 중심 점 근처 로 이동 해 야 한다.중간 은 확실히 말단(사라 짐)이 고 오른쪽 에 있 는 작은 공 은 중간 근처에 나타난다.
위 에서 분석 한 논리 에 따 르 면 저 는 애니메이션 의 총 진 도 를 6 부 로 나 누 었 는데 왜 6 부 입 니까?위의 애니메이션 분석 을 통 해 작은 공 은 과정 을 거 쳐 야 한 다 는 것 을 알 수 있다.
4.567917.출현(무 그 라 데 이 션 에서 초기 크기 로)
이렇게 되면 등장 과 사라 짐 은 1/3 애니메이션 진 도 를 차 지 했 고 다른 두 부분 은 각각 1/3 애니메이션 진 도 를 차지 했다.예 를 들 어 애니메이션 을 시작 할 때 가장 왼쪽 에 있 는 작은 공 을 1 로 설정 하고 중간 에 있 는 작은 공 은 2 이 며 가장 오른쪽 에 있 는 작은 공 은 3 이다.
작은 공 1 이 중심 점 으로 이동 할 때 애니메이션 은 1/3 을 진행 했다.그러면 이때 의 작은 공 2 는 말단 으로 이동 해 야 하고 작은 공 3 은 사라 지고 나타 나 는 과정 을 겪 었 기 때문에 좌표 축의 출발점 에 나타 나 야 한다.
이 를 통 해 알 수 있 듯 이 처음에 있 었 던 상황(작은 공 하 나 는 왼쪽 에 있 고 하 나 는 가운데 에 있 으 며 하 나 는 오른쪽 에 있다)은 색깔 이 다 를 뿐이다.이런 유추 로 무한 순환 하면 아름 다운 애니메이션 을 형성 할 수 있다.
이런 것들 을 분석 해 내 면 무슨 소 용이 있 습 니까?나 는 좌표 로 작은 공의 이동 을 확정 하 는 데 작은 문제 가 있 을 수 있다 는 것 을 알 았 기 때문에 애니메이션 의 진도 로 이 루어 졌 다.다음은 구체 적 인 실현 을 살 펴 보 자.
작은 공의 무한 운동 을 실현 해 야 합 니 다.가장 실 용적 인 것 은 애니메이션 으로 이 루어 지 는 것 입 니 다.여기 서 저 는 속성 애니메이션 을 사 용 했 습 니 다.Animotor 클래스 초기 화:
#RefreshView.java
private void initAnimator() {
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(1500);
animator.setRepeatCount(-1);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setInterpolator(new LinearInterpolator());
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
prepareToStart(); // View
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
for (Circle circle : mCircles) {
updateCircle(circle, mCircles.indexOf(circle), animation.getAnimatedFraction());
}
postInvalidate();
}
});
mAnimator = animator;
}
이것 은 무한 순환 애니메이션 으로 수 동 으로 멈 추 지 않 으 면 계속 순환 하 는 것 을 볼 수 있다.mAnimator 에 대해 서 는 모니터 도 추가 되 었 습 니 다.애니메이션 을 시작 할 때 prepareToStart()방법 을 사용 하 는 것 입 니 다.이 방법 은 낯 이 익 지 않 습 니까?맞습니다.바로 우리 위 에 resetCircles()에서 작은 공의 형 태 를 STATE 로 판단 하 는 것 입 니 다.PREPARED 는 호출 된 것 으로,이 방법 은 작은 공이 새로 고침 의 임계 점 에 도달 하도록 확보 할 것 이다.UpdateLisener 의 onAnimationUpdate()방법 중의 updateCircle()방법 을 살 펴 보 겠 습 니 다.#RefreshView
private void updateCircle(Circle circle, int index, float fraction) {
float progress = fraction; //
float virtualFraction; //
switch (index) {
case LEFT:
if (fraction < 5f / 6f) {
progress = progress + 1f / 6f;
} else {
progress = progress - 5f / 6f;
}
break;
case CENTER:
if (fraction < 0.5f) {
progress = progress + 0.5f;
} else {
progress = progress - 0.5f;
}
break;
case RIGHT:
if (fraction < 1f / 6f) {
progress += 5f / 6f;
} else {
progress -= 1f / 6f;
}
break;
}
if (progress <= 1f / 6f) {
virtualFraction = progress * 6;
appear(circle, virtualFraction);
return;
}
if (progress >= 5f / 6f) {
virtualFraction = (progress - 5f / 6f) * 6;
disappear(circle, virtualFraction);
return;
}
virtualFraction = (progress - 1f / 6f) * 3f / 2f;
move(circle, virtualFraction);
}
나 는 하나의 virtual Fraction 을 사용 하여 모든 작은 공의 가상 진 도 를 나 타 냈 다.예 를 들 어 애니메이션 의 전체 진도 가 0 일 때 왼쪽 작은 공의 가상 진 도 는 1/6+0(기본 적 으로 나타 나 는 과정 을 거 쳤 고 1/6 소모)이 어야 한다.중간 작은 공의 가상 진 도 는 1/6+1/3+0=1/2(기본 적 으로 나타 나 는 과정 을 거 쳤 다.중간 으로 이동)가장 오른쪽 작은 공의 가상 진 도 는 1/6+1/3+1/3+0=5/6 이다.그 다음 에 애니메이션 의 전체 진도 가 1/3 에 이 르 렀 을 때 왼쪽 공의 가상 진 도 는 1/2(중간 위치)이다.다음은 move(),appeared(),disapear()방법 을 살 펴 보 겠 습 니 다.
#RefreshView
private void appear(Circle circle, float fraction) {
circle.r = (int) (mMinRadius * fraction);
circle.x = mMinRadius;
}
private void disappear(Circle circle, float fraction) {
circle.r = (int) (mMinRadius * (1 - fraction));
}
private void move(Circle circle, float fraction) {
int difference = mMaxRadius - mMinRadius;
if (fraction < 0.5) {
circle.r = (int) (mMinRadius + difference * fraction * 2);
} else {
circle.r = (int) (mMaxRadius - difference * (fraction - 0.5) * 2);
}
circle.x = (int) (mMinRadius + mGap * 2 * fraction);
}
이 세 가지 방법 은 모두 매우 간단 해서 좌표 의 비례 에 따라 작은 공의 좌표 와 크기 를 계산한다.이상 은 전체 Refresh View 의 실현 입 니 다.원본 코드 를 볼 필요 가 있 으 면 문 말 까지 끌 어 올 릴 수 있 습 니 다.
4 사용 및 효과
어떻게 사용 하 는 지 보기:
#MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRefreshView = findViewById(R.id.refresh_view);
// mRefreshView.setOriginState(RefreshView.STATE_PREPARED);
Button start = findViewById(R.id.start);
Button stop = findViewById(R.id.stop);
SeekBar seekBar = findViewById(R.id.seek_bar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mRefreshView.drag(progress / 100f);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
start.setOnClickListener(this);
stop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start:
mRefreshView.start();
break;
case R.id.stop:
mRefreshView.stop();
break;
}
}
효과 그림:녹화 소프트웨어 의 문제 로 녹색 작은 공 은 효과 가 좋 지 않 아 휴대 전화 나 가상 컴퓨터 에 표시 되 는 것 이 정상 적 이다.프로젝트 의 실제 운용 효 과 를 다시 봅 니 다.
녹화 프로그램 이 녹색 에 알레르기 가 있 는 것 같 으 니 한 번 보 세 요.
이 글 은 여기 서 끝 났 습 니 다.읽 어 주 셔 서 감사합니다.
데모 주소:https://github.com/gminibird/RefreshViewTest ( 로 컬 다운로드 )
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.