Android 는 Path 를 사용 하여 동적 으로 애니메이션 을 불 러 오 는 검색 효 과 를 실현 합 니 다.
이것 을 실현 하 는 것 은 Path 의 getSegment()를 사용 하여 세 션 을 캡 처 한 start 와 stop 을 계속 바 꾸 고 애니메이션 과 결합 하여 오늘 절차 에 따라 이 를 실현 하 는 것 입 니 다.보고 나 면 어렵 지 않 을 것 입 니 다.다만 이렇게 실현 할 줄 몰 랐 을 뿐 입 니 다.시야 가 당신 의 높이 를 결정 하 는 지,아니면 제 가 블 로 그 를 쓰 는 습관 을 이 어 가 는 지 한 걸음 한 걸음 분석 하 는 것 입 니 다.첫 번 째 단 계 는 다음 과 같은 그림 을 그 리 는 것 입 니 다.
단순히 이 그림 을 그리 면 간단 하고 간단 합 니 다.원 을 그리고 선 을 하나 더 그리 면 됩 니 다.하지만 여기 의 효 과 를 고려 해 야 합 니 다.이렇게 하면 안 됩 니 다.위의 gif 그림 을 보면 알 수 있 습 니 다.사실은 이것 은 2 개의 동심원 입 니 다.그리고 앞의 path 의 출발점 과 뒤의 path 의 출발점 이 연결 되면 직선 이 됩 니 다.그런데 path 의 도형 내용 이 바로 이 원 입 니 다.어떻게 그 려 졌 나 요?원 을 그 리 는 것 이 라면 위의 선 출발점 과 종점 위 치 를 어떻게 계산 하 느 냐 가 문제 입 니 다.그러나 우리 가 원 을 그 리 는 것 은 타원 을 그 리 는 형식 으로 도 원 을 그 릴 수 있 습 니 다.45 도 에서 원 을 그 릴 수 있 습 니 다.이 선의 출발점 이 맞 는 지 분석 도 는 다음 과 같 습 니 다.
좋 습 니 다.위의 분석 에 따라 코드 를 작성 하여 정적 검색 그림 을 그립 니 다.
package com.tuya;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by admin on 2016/12/17.
*/
public class DynamicSearchView2 extends View {
private Paint paint;
private int width;//view
private int height;//view
private Path searchPath;
private Path circlePath;
private float BigCircleRectWidth;//
private PathMeasure pathMeasure;
private float[] pos;
public DynamicSearchView2(Context context) {
this(context,null);
}
public DynamicSearchView2(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
initPath();
}
/**
* path
*/
private void initPath() {
searchPath = new Path();
circlePath = new Path();
if(width>height){//
BigCircleRectWidth = height;
}else if(width<height){
BigCircleRectWidth = width;
}else{
BigCircleRectWidth = width;
}
float smallbordWidth =BigCircleRectWidth/8;
RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);
searchPath.addArc(searchRect,45,360);
float bigBordWidth = smallbordWidth*2;
RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);
circlePath.addArc(circleRect,45,-360);
pathMeasure = new PathMeasure(circlePath,false);
pos = new float[2];
pathMeasure.getPosTan(0,pos,null);
searchPath.lineTo(pos[0],pos[1]);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(width/2,height/2);// view
canvas.drawPath(searchPath,paint);
canvas.drawPath(circlePath,paint);
}
}
효과 그림:원래 이 바깥 원 은 그 릴 필요 가 없 었 다.나 는 여기 서 그 려 서 이 두 원 이 일정한 관 계 를 가지 고 있다 는 것 을 알려 주 었 을 뿐 인 데 왜 이 선 이 이 렇 습 니까?우리 가 이 원 을 그 릴 때 45 도 에서 360 도 를 그 리 는 것 이 딱 일주일 이 었 다.원 을 만 들 었 다.지금 테스트 를 할 때 360 도 말고 330 도 를 쓰 면 효 과 는 다음 과 같다.
이때 너 는 이 선 이 옳다 는 것 을 알 게 될 것 이다.문 제 를 야기 하 는 것 은 사실은 이렇다.그림 분석 과 같다.
타원 을 그 리 는 키 코드:
searchPath.addArc(searchRect,45,358);
circlePath.addArc(circleRect,45,-358);
360 으로 쓰 지 말고 358 로 바 꿔 보 세 요.효과 도:이 선 이 정상 인지 아 닌 지 알 게 되 었 습 니 다.바깥 에 있 는 원 에 약간의 결함 이 있 습 니 다.첫째,358 을 359 로 바 꾸 면 괜 찮 을 것 입 니 다.그리고 우리 의 실제 효 과 는 이 바깥 의 원 이 필요 하지 않 기 때문에 고치 지 않 아 도 괜 찮 습 니 다.그러면 좋 습 니 다.첫 번 째 단 계 는 완성 한 셈 입 니 다.지금 두 번 째 단계 가 어떻게 실현 되 는 지 생각 하고 있 습 니 다.먼저 두 번 째 단계 의 효 과 를 gif 로 보 여 주세요.그렇지 않 으 면 생각 만 하고 생각 만 하지 않 습네가 미녀 를 보 는 것 처럼 첫눈 에 그것 을 보 았 지,그렇지,더 이상 말 하지 않 겠 다!화면 감 있 게...
아니면 캔버스 분석:
어디 에 우리 가 startD 라 는 시작 점 에서 의 위치 값 을 바 꾸 면 ok 입 니 다.물론 여러 가지 방법 이 있 습 니 다.그러나 Android 에 서 는 기본적으로 값 애니메이션 을 사용 합 니 다.ok.이 사고 에 따라 이 두 번 째 논 리 를 실현 합 니 다.
package com.tuya;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by admin on 2016/12/17.
*/
public class DynamicSearchView2 extends View {
private Paint paint;
private int width;//view
private int height;//view
private Path searchPath;
private Path circlePath;
private float BigCircleRectWidth;//
private PathMeasure pathMeasure;
private float[] pos;
private float animPercent;//
private ValueAnimator serchStartAnim;
private long animDuration = 2000;//
public DynamicSearchView2(Context context) {
this(context,null);
}
public DynamicSearchView2(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
initPaint();
initAnim();
initAnimListener();
startAnim();
}
/**
*
*/
private void startAnim() {
serchStartAnim.start();
}
/**
*
*/
private void initAnimListener() {
serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// ,
animPercent = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
}
/**
*
*/
private void initAnim() {
serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
}
/**
*
*/
private void initPaint() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
initPath();
}
/**
* path
*/
private void initPath() {
searchPath = new Path();
circlePath = new Path();
if(width>height){//
BigCircleRectWidth = height;
}else if(width<height){
BigCircleRectWidth = width;
}else{
BigCircleRectWidth = width;
}
float smallbordWidth =BigCircleRectWidth/8;
RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);
searchPath.addArc(searchRect,45,358);
float bigBordWidth = smallbordWidth*2;
RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);
circlePath.addArc(circleRect,45,-358);
pathMeasure = new PathMeasure(circlePath,false);
pos = new float[2];
pathMeasure.getPosTan(0,pos,null);
searchPath.lineTo(pos[0],pos[1]);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(width/2,height/2);// view
drawSearch(canvas);
}
private void drawSearch(Canvas canvas) {
Path dst = new Path();
pathMeasure.setPath(searchPath,false);
pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);
canvas.drawPath(searchPath,paint);
}
}
효과:지금 은 우리 의 효과 가 아직 바깥 원 의 큰 원 의 효과 가 부족 하 다.그러면 큰 원 은 작은 원 애니메이션 이 실 행 된 후에 회전 효 과 를 하 는 것 이다.좋아,우 리 는 애니메이션 만 감청 하면 돼.그림 을 그 려.
package com.tuya;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by admin on 2016/12/17.
*/
public class DynamicSearchView2 extends View {
private static final String TAG = "DynamicSearchView2";
private Paint paint;
private int width;//view
private int height;//view
private Path searchPath;
private Path circlePath;
private float BigCircleRectWidth;//
private PathMeasure pathMeasure;
private float[] pos;
private float animPercent;//
private ValueAnimator serchStartAnim;
private ValueAnimator bigCircleAnim;//
private long animDuration = 2000;//
private int drawTag = 1;//
public DynamicSearchView2(Context context) {
this(context,null);
}
public DynamicSearchView2(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
initPaint();
initAnim();
initAnimListener();
startAnim();
}
/**
*
*/
private void startAnim() {
drawTag = 1;
serchStartAnim.start();
invalidate();
}
/**
*
*/
public void startBigCirCleAnim(){
serchStartAnim.removeAllUpdateListeners();// bug
bigCircleAnim.start();
drawTag = 2;
}
/**
*
*/
private void initAnimListener() {
serchStartAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
startBigCirCleAnim();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// ,
animPercent = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
bigCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// ,
animPercent = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
}
/**
*
*/
private void initAnim() {
bigCircleAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
}
/**
*
*/
private void initPaint() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
initPath();
}
/**
* path
*/
private void initPath() {
searchPath = new Path();
circlePath = new Path();
if(width>height){//
BigCircleRectWidth = height;
}else if(width<height){
BigCircleRectWidth = width;
}else{
BigCircleRectWidth = width;
}
float smallbordWidth =BigCircleRectWidth/8;
RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);
searchPath.addArc(searchRect,45,358);
float bigBordWidth = smallbordWidth*2;
RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);
circlePath.addArc(circleRect,45,-358);
pathMeasure = new PathMeasure(circlePath,false);
pos = new float[2];
pathMeasure.getPosTan(0,pos,null);
searchPath.lineTo(pos[0],pos[1]);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(width/2,height/2);// view
drawSearch(canvas);
}
private void drawSearch(Canvas canvas) {
if(drawTag==1){
drawSearchGraph(canvas);
}else if(drawTag==2){
drawBigCircleGraph(canvas);
}
}
/**
*
* @param canvas
*/
private void drawBigCircleGraph(Canvas canvas) {
pathMeasure.setPath(circlePath, false);
Path dst2 = new Path();
float stop = pathMeasure.getLength() * animPercent;
float start = (float) (stop - ((0.5 - Math.abs(animPercent - 0.5)) * 200f));
pathMeasure.getSegment(start, stop, dst2, true);
canvas.drawPath(dst2, paint);
}
/**
*
* @param canvas
*/
private void drawSearchGraph(Canvas canvas) {
pathMeasure.setPath(searchPath,false);
Path dst = new Path();
pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);
canvas.drawPath(dst,paint);
}
}
효과:한 바퀴 돌 면 끝 이 야.특정한 수요 가 있 으 면 전체 바퀴 의 동 그 라 미 를 통제 해 야 해.인터넷 로 딩 이 라면 인터넷 이 특별히 좋 지 않 으 면 상관 하지 않 아.이따가 주 보 를 써 야 하 니까 고 통 스 러 워.
아직 마지막 단 계 는 대원 의 운동 이 끝 난 후에 검색 상 자 를 그 리 는 것 입 니 다.사실 이것 은 첫 번 째 효과 와 딱 관련 이 있 습 니 다.
package com.tuya;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by admin on 2016/12/17.
*/
public class DynamicSearchView2 extends View {
private static final String TAG = "DynamicSearchView2";
private Paint paint;
private int width;//view
private int height;//view
private Path searchPath;
private Path circlePath;
private float BigCircleRectWidth;//
private PathMeasure pathMeasure;
private float[] pos;
private float animPercent;//
private ValueAnimator serchStartAnim;
private ValueAnimator bigCircleAnim;//
private ValueAnimator startDrawSearchAnim;//
private long animDuration = 2000;//
private int drawTag = 1;//
public DynamicSearchView2(Context context) {
this(context,null);
}
public DynamicSearchView2(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
initPaint();
initAnim();
initAnimListener();
startAnim();
}
/**
*
*/
private void startAnim() {
drawTag = 1;
serchStartAnim.start();
invalidate();
}
/**
*
*/
public void startBigCirCleAnim(){
serchStartAnim.removeAllUpdateListeners();// bug
bigCircleAnim.start();
drawTag = 2;
}
/**
*
*/
public void drawSearchAanim(){
bigCircleAnim.removeAllUpdateListeners();// bug
startDrawSearchAnim.start();
drawTag = 3;
}
/**
*
*/
private void initAnimListener() {
bigCircleAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
drawSearchAanim();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// ,
animPercent = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
serchStartAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
startBigCirCleAnim();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// ,
animPercent = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
bigCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// ,
animPercent = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
startDrawSearchAnim .addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// ,
animPercent = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
}
/**
*
*/
private void initAnim() {
bigCircleAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
startDrawSearchAnim = ValueAnimator.ofFloat(1,0).setDuration(animDuration);
}
/**
*
*/
private void initPaint() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(6);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
initPath();
}
/**
* path
*/
private void initPath() {
searchPath = new Path();
circlePath = new Path();
if(width>height){//
BigCircleRectWidth = height;
}else if(width<height){
BigCircleRectWidth = width;
}else{
BigCircleRectWidth = width;
}
float smallbordWidth =BigCircleRectWidth/8;
RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);
searchPath.addArc(searchRect,45,358);
float bigBordWidth = smallbordWidth*2;
RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);
circlePath.addArc(circleRect,45,-358);
pathMeasure = new PathMeasure(circlePath,false);
pos = new float[2];
pathMeasure.getPosTan(0,pos,null);
searchPath.lineTo(pos[0],pos[1]);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(width/2,height/2);// view
drawSearch(canvas);
}
private void drawSearch(Canvas canvas) {
if(drawTag==1){
drawSearchGraph(canvas);
}else if(drawTag==2){
drawBigCircleGraph(canvas);
}else if(drawTag==3){
drawSearchBox(canvas);
}
}
/**
*
* @param canvas
*/
private void drawSearchBox(Canvas canvas) {
pathMeasure.setPath(searchPath, false);
Path dst3 = new Path();
pathMeasure.getSegment(pathMeasure.getLength() * animPercent, pathMeasure.getLength(), dst3, true);
canvas.drawPath(dst3, paint);
}
/**
*
* @param canvas
*/
private void drawBigCircleGraph(Canvas canvas) {
pathMeasure.setPath(circlePath, false);
Path dst2 = new Path();
float stop = pathMeasure.getLength() * animPercent;
float start = (float) (stop - ((0.5 - Math.abs(animPercent - 0.5)) * 200f));
pathMeasure.getSegment(start, stop, dst2, true);
canvas.drawPath(dst2, paint);
}
/**
*
* @param canvas
*/
private void drawSearchGraph(Canvas canvas) {
pathMeasure.setPath(searchPath,false);
Path dst = new Path();
pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);
canvas.drawPath(dst,paint);
}
}
효과:github: https://github.com/zhouguizhi/PathSearch
총결산
위 에서 말 한 것 은 소 편 이 여러분 에 게 소개 한 안 드 로 이 드 가 Path 를 사용 하여 동적 으로 애니메이션 을 불 러 오 는 효 과 를 실현 하 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 저 에 게 메 시 지 를 남 겨 주세요.소 편 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.