Android 는 좌우 로 흔 들 리 는 구체 애니메이션 효 과 를 실현 합 니 다.

우선 효과 부터 볼 게 요.
这里写图片描述  
아마 여러분 들 은 다른 곳 에서 비슷 한 것 을 보 셨 을 것 입 니 다.저 는 위 챗 의 글 말미 에 물건 이 있 는 것 을 보 았 습 니 다.재 미 있 으 면 코드 로 이 루어 보 겠 습 니 다.이 글 은 주로 코드 를 쓰 는 사고방식 을 파악 하여 보 여 준다.
위의 그림 을 보면 여러분 이 생각 할 수 있 는 가장 간단 한 실현 방안 은 바로 애니메이션 으로 많은 그림 을 자 른 다음 에 쉽게 실현 할 수 있 을 것 이 라 고 생각 합 니 다.더 이상 편안 한 곳 에 있 지 않도록 귀 찮 게 하 라.계산 을 통 해 이 루어 진다.글 의 끝 에 모든 코드 를 붙 여 복사 하면 바로 실행 할 수 있 습 니 다.
추억의 지식 이 필요 하 다
중력 위치 에너지 E=mgh
운동 에너지 E=½mv²
이상 적 인 상태 에서 운동 에너지 와 중력 식 은 서로 전환 할 수 있 고 에너지 도 보존 할 수 있다.
세부 사항 에 너무 주의 하지 않 으 려 면 이상 의 지식 을 소홀히 해도 된다.
프로 세 스 그리 기
끈 달 린 공 5 개 그리 기
这里写图片描述  
이 단 계 는 매우 간단 하 다.요약 하면:
공의 원심 좌표 확인 O
고정 길이 의 라인 을 그 려 주세요.OA.
점 O 를 원심 으로 하여 반경 을 고정 시 키 는 공 을 그린다.
여러 줄 공 그리 기
관련 코드 는 글 의 끝 에 이미 붙 어 있다(78-121 줄,코드 에 후속 적 인 세부 처리 가 있 으 므 로 관련 코드 를 선별 해 야 한다).여 기 는 생각 만 쓰 고 중복 되 지 않 는 다.
코드 붙 였 어.
공 을 돌리다
这里写图片描述
정적 그림:
这里写图片描述  
끈 이 달 린 공 을 회전 시 키 는 것 은 사실상 위의 그림 의 각 을 바 꾸 는 것 이다.α;...해 야 한다α클 수록 오프셋 의 각도 가 크다....해 야 한다α작 을 수록 편 이의 각도 가 작 아진 다.
계산 을 간단하게 하기 위해 먼저 전 제 를 가설 하 다.
1.α의 최대 치 는 45°이다.
2.매번 화면 새로 고침α변 경 된 값 의 크기 가 일치 하고 1(즉,invalidate()방법 을 호출 합 니 다)
3.처음부터α45°입 니 다.
이러한 전제 제한 이 있 습 니 다.실제로 그림 을 그 릴 때마다 우리 가 알 고 있 는 조건 은:
1.O 점 의 좌표
2.큰 원 의 반지름=끈 의 길이+작은 원 의 반지름
3.α값α벌 렁 벌 렁
그래서 이 단계 의 대체적인 절 차 는 다음 과 같다.
1.큰 원 의 원심 O,반경 R 에 따라 현재α의 각도 에서 B 점 의 좌 표를 구한다(전편 과 유사 하 게 호 를 그리고 PathMeasure.getPosTan()을 통 해 해당 점 의 좌 표를 얻는다)
2.선분 OB 그리 기
3.B 점 을 원심 으로 하고 반경 을 고정 값 으로 하 는 작은 원 을 그린다.
관련 코드 는 글 의 끝 에 이미 붙 어 있 습 니 다(128-212 줄,코드 에 후속 적 인 세부 처리 가 있 으 므 로 관련 코드 를 선별 해 야 합 니 다).여 기 는 생각 만 쓰 고 더 이상 무 겁 지 않 습 니 다.
코드 를 다시 붙 였 습 니 다.
현실 을 모방 하 다
지난 단계 에서 우 리 는 모델 을 간소화 하기 위해α의 변 화 량 은 매번 1 이지 만 현실 과 맞지 않 는 다.현실 상황 은 이렇다.
1.공이 최고점 으로 이동 할 때 속도 가 느 리 고 기본적으로 0 이다.
2.공이 가장 낮은 곳 으로 이동 하고 속도 가 가장 빠르다.
这里写图片描述
글 이 시작 되 자마자 우 리 는 추억 이 필요 한 지식 을 준비 했다.이제 물리학 수업 으로 돌아 가 간단 한 시계 모형 계산 을 말 해 보 자.
这里写图片描述  
조건:끈 의 길 이 는 L 이 고 공 A 가 정지 할 때 세로 방향의 협각 은?α
구:수직 방향 과 의 협각 은?β시 각속도
这里写图片描述
문제 풀이 절차 총 기계 에너지 구하 기
这里写图片描述
공이 정지 할 때 기계 에너지
这里写图片描述
일반적인 상황 의 표시
공이 운동 할 때 기계 에너지=중력 위치 에너지+운동 에너지
这里写图片描述  
또 공식 이 있다.
这里写图片描述  
그래서 최종 결 과 는:
这里写图片描述
자,결론 을 내 렸 습 니 다.코드 로 돌아 갑시다.

//       
float v = (float) Math.sqrt(2 * 9.8 * L * (Math.cos( β* Math.PI / 180) - cos(α* Math.PI / 180)));
//     
float w = v / L;
설명:여 기 는 의합 일 뿐 특별히 정확 하지 않다.우 리 는 현재 각도 에서 변 경 된 각도 사이 의 각 속도 가 일치 하고 모두 현재 각도 에 대응 하 는 각 속도 라 고 생각한다.
그래서 현재 각도 에서 각 도 를 바 꾸 는 양은 다음 과 같다.这里写图片描述 
구체 적 인 실현 과정 은 아래 코드 의 219-225 줄 에 있 습 니 다.간단 하지 않 습 니까?
모든 코드
위 에서 한참 동안 잔소리 하 다가 마침내 복제 할 수 있 는 것 을 주 었 다 O(∩∩)O~

/**
* Created by kevin on 2016/9/2.
* <p>
*        :
* 1.           
* 2.           
* 3.      ,                   
*/
public class Pendulum extends View {
private Paint linePaint;
private int width;
private int height;
private Path linePath;//         Path
private Path bigCirclePath;//       Path
private Path rotateLinePath;//         Path
private int stroke = 5; //     
private int r = 20; //     
private int length = 200; //    
private int number = 5; //    (  ,         )
private static int angle = 50;//      
//          ;            ,            
// +angle             30 
// -angle             30 
//          ;-1        ,1        
private float[] degree = new float[]{angle, -1};
private float t = 2f;//  ;        ,t  ,    ;t  ,    
private float cosO;//cosθ,     
private float gr2;//2gr,     
public Pendulum(Context context) {
super(context);
initPaint();
calCosOAnd2gr();
}
public Pendulum(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
calCosOAnd2gr();
}
public Pendulum(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
calCosOAnd2gr();
}
/**
*     cosθ 2gr
*/
private void calCosOAnd2gr() {
//      cosα-cosθ=0   ,  +0.1
cosO = (float) Math.cos((angle + 0.1f) * Math.PI / 180);
//2           
gr2 = (float) (9.8 * r * 2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(width / 2, height / 2);
drawPic(canvas);
rotate(canvas);
}
/**
*       
*
* @param canvas
*/
private void drawPic(Canvas canvas) {
if (number < 1) {
throw new IllegalArgumentException("      1");
}
int x;
if (number % 2 == 1) {
//     
//          ,  :  number 3,leftNumber 1
// number 5,leftNumber 2
// number 7,leftNumber 3
int leftNumber = number / 2;
for (int i = -leftNumber; i <= leftNumber; i++) {
if (isRight()) {
//      
if (i == leftNumber)
continue;
} else if (!isRight()) {
//       
if (i == -leftNumber)
continue;
}
//        x
x = 2 * r * i;
if (linePath == null)
linePath = new Path();
linePath.reset();
//move   (       (x,-r),             ;          ,        )
linePath.moveTo(x, 0);
//      ,(     =       +   )
linePath.lineTo(x, -(r + length));
//    
linePaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawPath(linePath, linePaint);
//    ,     ,  FILL,       
linePaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(x, 0, r, linePaint);
}
} else if (number % 2 == 0) {
//  
throw new IllegalArgumentException("    ,    ");
}
}
/**
*        
*
* @param canvas
*/
private void rotate(Canvas canvas) {
//               ,  direction(  +1 -1)    
int direction;
if (isRight()) {
//     ,+1
direction = 1;
} else {
//     ,-1
direction = -1;
}
//measure.getPosTan()      ,        
float nowDegree = Math.abs(degree[0]);
linePaint.setStyle(Paint.Style.STROKE);
//           
int pointNumber = number / 2;
//          , drawPic  (x = 2 * r * i)  
int x = 2 * r * pointNumber * direction;
//           ,           
float[] topPoint = new float[]{x, -(r + length)};
int totalLength = length + r;
if (bigCirclePath == null)
bigCirclePath = new Path();
bigCirclePath.reset();
//rectF        :         ,length + r      
RectF rectF = new RectF(topPoint[0] - totalLength, topPoint[1] - totalLength, topPoint[0] + totalLength, topPoint[1] + totalLength);
//  1/4     
bigCirclePath.addArc(rectF, 90, -90 * direction);
//      nowDegree      ;
float[] rotatePoint = new float[2];
PathMeasure measure = new PathMeasure(bigCirclePath, false);
//  ,rotatePoint                 
measure.getPosTan(measure.getLength() * (nowDegree) / 90, rotatePoint, null);
//     ,                      。
//  ,          ,  rotatePoint     
//   
if (rotateLinePath == null)
rotateLinePath = new Path();
rotateLinePath.reset();
rotateLinePath.moveTo(topPoint[0], topPoint[1]);
rotateLinePath.lineTo(rotatePoint[0], rotatePoint[1]);
canvas.drawPath(rotateLinePath, linePaint);
//  
linePaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(rotatePoint[0], rotatePoint[1], r, linePaint);
//      ,    
linePaint.setTextSize(40);
canvas.drawText("     :" + degree[0] + "", -100, 100, linePaint);
//degree[1]    ,  1 ,        ,  degree[0]      (      ;       ,         ,            )
if (degree[1] == 1) {
//    ,degree  
if (degree[0] < angle) {
//         
float changeAngle = rotateAngle();
//        
degree[0] = degree[0] + changeAngle;
invalidate();
}
//       ,    
if (degree[0] >= angle) {
degree[1] = -1;
}
}
//degree[1]    ,  -1 ,        ,  degree[0]      (      ;       ,         ,            )
else if (degree[1] == -1) {
//    ,degree  
if (degree[0] > -angle) {
//         
float changeAngle = rotateAngle();
//        
degree[0] = degree[0] - changeAngle;
invalidate();
}
//       ,    
if (degree[0] <= -angle) {
degree[1] = 1;
}
}
}
/**
*            
*
* @return
*/
private float rotateAngle() {
//       
float v = (float) Math.sqrt(gr2 * (Math.cos(Math.abs(degree[0]) * Math.PI / 180) - cosO));
//         
float changedAngle = t * v / r;
return changedAngle;
}
/**
*             
*
* @return true-->       
* false-->       
*/
private boolean isRight() {
boolean flag = false;
//degree[0]  0,       
//degree[1]  0,       
if (degree[0] > 0) {
flag = true;
} else if (degree[0] < 0) {
flag = false;
} else if (degree[0] == 0) {
//  degree  0,              
//degree[1]  -1  :         ,  ,     v-->0,         
if (degree[1] == -1) {
flag = true;
}
//        ,       
else if (degree[1] == 1) {
flag = false;
}
}
return flag;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
private void initPaint() {
//       Paint,    Paint    ,     ,    Paint        
linePaint = new Paint();
linePaint.setStrokeWidth(stroke);
linePaint.setAntiAlias(true);
linePaint.setStyle(Paint.Style.FILL_AND_STROKE);
linePaint.setColor(0xff4897fe);
}
}
위 에서 말 한 것 은 소 편 이 소개 한 안 드 로 이 드 가 좌우 로 흔 들 리 는 구체 애니메이션 효 과 를 실현 하 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.소 편 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기