Android WaveView 수류 파동 효과 구현

12506 단어 AndroidWaveView물결
수류 파동 의 파형 은 모두 삼각 파 이 며 곡선 은 정 여현 곡선 이지 만 안 드 로 이 드 에 서 는 정 여현 곡선 을 그 리 는 API 를 제공 하지 않 았 다.Path 류 에 서 는 베 어 셀 곡선 을 그 리 는 방법 quadTo 가 있 는데 2 단계 베 어 셀 곡선 을 그 렸 다.파동 효 과 를 실현 하려 면 Path 곡선 만 그 릴 수 있다.2 단계 의 베 세 르 곡선 이 어떻게 된 일 인지 잠시 후에 설명 하 겠 습 니 다.먼저 실현 효 과 를 살 펴 보 겠 습 니 다.

이 파장 은 비교적 짧 아서 아직 기복 이 보이 지 않 고 단지 출 렁 일 뿐 이 니 파장 을 길 게 늘 려 서 다시 한 번 보 자.

기복 이 뚜렷 한 것 을 볼 수 있 습 니 다.다시 길 게 당 겨 보 세 요.

이것 은 기복 감 이 비교적 강하 다.이 파동 효 과 를 이용 하여 수위 선 을 그 릴 때 사용 할 수 있 고 파동 의 진도 바 WaveUpProgress 도 만 들 수 있 습 니 다.예 를 들 어 다음 과 같 습 니 다.

너무 역 동적 이지 않 아 요?
그럼 이런 파동 효 과 는 어떻게 하 는 거 예요?앞에서 말 한 베 세 르 곡선 은 도대체 무엇 일 까?다음은 일일이 설명 하 겠 습 니 다.베 세 르 곡선 을 잘 사용 하려 면 표현 식 을 먼저 이해 해 야 한다.이미지 설명 을 위해 서 나 는 인터넷 에서 동 도 를 훔 쳤 다.
우선 1 단계 베 세 르 곡선의 표현 식 을 보십시오.
                             
t 의 변화 에 따라 실제 적 으로 P0 에서 P1 까지 의 직선 구간 입 니 다.
                                
Android 에서 Path 의 quadTo 는 3 시의 2 단계 베 세 르 곡선 입 니 다.그러면 2 단계 표현 식 은 다음 과 같 습 니 다.
   
복잡 해 보 여서 나 는 그것 을 나 누 어 보 았 다.
        
그리고 이렇게 합 친다.
      
뭐 봤 죠?눈치 채 지 못 하면 이렇게 바 꿉 니 다.
     
      
     
B0 과 B1 은 각각 P0 에서 P1,P1 에서 P2 까지 의 1 단계 베 셀 곡선 이다.2 단계 베 세 르 곡선 B 는 B0 에서 B1 까지 의 1 단계 베 세 르 곡선 이다.분명히 그의 동태 도 를 나타 내 면 이해 하기 어렵 지 않다.
                                          
붉 은 점 의 운동 궤적 은 바로 B 의 궤적 이다.이것 이 바로 2 단계 베 세 르 곡선 이다.P1 이 P0 과 P2 의 수직 이등분선 에 있 을 때 B 는 입 을 열 어 위로 또는 아래로 향 하 는 포물선 이다.WaveView 에 서 는 입 을 위로 향 하고 아래로 향 하 는 포물선 으로 수 파 를 모 의 한다.Android 에서 Path 를 사용 하 는 방법 은 우선 path.moveto(P0),그리고 path.quadTo(P1,P2),canvas.drawPath(path,paint)곡선 이 나 옵 니 다.여러 개의 베 어 셀 곡선 을 그 리 려 면 끊임없이 quadTo 를 그 려 보 세 요.
    베 세 르 곡선 을 말 한 후에 물 파동 의 효과 가 어떻게 생 겼 는 지 이야기 하기 시작 해 야 한다.먼저 기계 파 의 전송 은 매체 의 진동 을 통 해 파형 을 전송 방향 으로 이동 시 키 는 것 이다.모든 진동 주기 파형 은 마침 하나의 파장 을 평평 하 게 이동 하고 모든 매체 점 은 다시 한 주기 전의 상태 로 돌아 가 는 것 이다.그래서 물 파동 효 과 를 실현 하려 면 파형 을 평평 하 게 옮 기 면 된다.
그렇다면 WaveView 의 실현 원 리 는 다음 과 같다.
    먼저 View 에서 View 너비 계산 에 따라 몇 개의 완전한 파형 을 수용 할 수 있 고 하나 가 부족 한 것 은 하 나 를 계산 한 다음 에 View 의 보이 지 않 는 곳 에 완전한 파형 을 미리 남 길 수 있다.그 다음 에 파동 이 시 작 될 때 모든 점 을 x 방향 에서 똑 같은 거 리 를 이동 하면 숨겨 진 파형 이 평평 하 게 이동 되 고 이동 거리 가 하나의 파장 에 이 르 렀 을 때 모든 점 의 x 좌 표를 이동 전의 값 으로 회복 하면 하나의 파형 이 하나의 파형 으로 밖으로 전송 할 수 있다.스케치 로 다음 과 같이 표시 합 니 다.

WaveView 의 원 리 는 위의 그림 에서 직관 적 으로 알 수 있다.P[2n+1],n>=0 은 모두 베 어 셀 곡선의 통제 점 이 고 빨 간 선 은 수위 선 이다.
원 리 를 알 고 나 면 코드 를 볼 수 있다.
WaveView.java:

package com.jingchen.waveview; 
 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Timer; 
import java.util.TimerTask; 
 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Paint.Align; 
import android.graphics.Paint.Style; 
import android.graphics.Region.Op; 
import android.graphics.Path; 
import android.graphics.RectF; 
import android.os.Handler; 
import android.os.Message; 
import android.util.AttributeSet; 
import android.view.View; 
 
/** 
 *        
 * 
 * @author chenjing 
 * 
 */ 
public class WaveView extends View 
{ 
 
 private int mViewWidth; 
 private int mViewHeight; 
 
 /** 
  *     
  */ 
 private float mLevelLine; 
 
 /** 
  *        
  */ 
 private float mWaveHeight = 80; 
 /** 
  *    
  */ 
 private float mWaveWidth = 200; 
 /** 
  *            
  */ 
 private float mLeftSide; 
 
 private float mMoveLen; 
 /** 
  *        
  */ 
 public static final float SPEED = 1.7f; 
 
 private List<Point> mPointsList; 
 private Paint mPaint; 
 private Paint mTextPaint; 
 private Path mWavePath; 
 private boolean isMeasured = false; 
 
 private Timer timer; 
 private MyTimerTask mTask; 
 Handler updateHandler = new Handler() 
 { 
 
  @Override 
  public void handleMessage(Message msg) 
  { 
   //         
   mMoveLen += SPEED; 
   //      
   mLevelLine -= 0.1f; 
   if (mLevelLine < 0) 
    mLevelLine = 0; 
   mLeftSide += SPEED; 
   //      
   for (int i = 0; i < mPointsList.size(); i++) 
   { 
    mPointsList.get(i).setX(mPointsList.get(i).getX() + SPEED); 
    switch (i % 4) 
    { 
    case 0: 
    case 2: 
     mPointsList.get(i).setY(mLevelLine); 
     break; 
    case 1: 
     mPointsList.get(i).setY(mLevelLine + mWaveHeight); 
     break; 
    case 3: 
     mPointsList.get(i).setY(mLevelLine - mWaveHeight); 
     break; 
    } 
   } 
   if (mMoveLen >= mWaveWidth) 
   { 
    //                 
    mMoveLen = 0; 
    resetPoints(); 
   } 
   invalidate(); 
  } 
 
 }; 
 
 /** 
  *     x          ,            
  */ 
 private void resetPoints() 
 { 
  mLeftSide = -mWaveWidth; 
  for (int i = 0; i < mPointsList.size(); i++) 
  { 
   mPointsList.get(i).setX(i * mWaveWidth / 4 - mWaveWidth); 
  } 
 } 
 
 public WaveView(Context context) 
 { 
  super(context); 
  init(); 
 } 
 
 public WaveView(Context context, AttributeSet attrs) 
 { 
  super(context, attrs); 
  init(); 
 } 
 
 public WaveView(Context context, AttributeSet attrs, int defStyle) 
 { 
  super(context, attrs, defStyle); 
  init(); 
 } 
 
 private void init() 
 { 
  mPointsList = new ArrayList<Point>(); 
  timer = new Timer(); 
 
  mPaint = new Paint(); 
  mPaint.setAntiAlias(true); 
  mPaint.setStyle(Style.FILL); 
  mPaint.setColor(Color.BLUE); 
 
  mTextPaint = new Paint(); 
  mTextPaint.setColor(Color.WHITE); 
  mTextPaint.setTextAlign(Align.CENTER); 
  mTextPaint.setTextSize(30); 
 
  mWavePath = new Path(); 
 } 
 
 @Override 
 public void onWindowFocusChanged(boolean hasWindowFocus) 
 { 
  super.onWindowFocusChanged(hasWindowFocus); 
  //      
  start(); 
 } 
 
 private void start() 
 { 
  if (mTask != null) 
  { 
   mTask.cancel(); 
   mTask = null; 
  } 
  mTask = new MyTimerTask(updateHandler); 
  timer.schedule(mTask, 0, 10); 
 } 
 
 @Override 
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
 { 
  super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
  if (!isMeasured) 
  { 
   isMeasured = true; 
   mViewHeight = getMeasuredHeight(); 
   mViewWidth = getMeasuredWidth(); 
   //             
   mLevelLine = mViewHeight; 
   //   View         
   mWaveHeight = mViewWidth / 2.5f; 
   //       View     View            ,           
   mWaveWidth = mViewWidth * 4; 
   //               
   mLeftSide = -mWaveWidth; 
   //         View          ,  n    
   int n = (int) Math.round(mViewWidth / mWaveWidth + 0.5); 
   // n     4n+1  ,                  ,    4n+5   
   for (int i = 0; i < (4 * n + 5); i++) 
   { 
    //  P0      P4n+4,  4n+5   
    float x = i * mWaveWidth / 4 - mWaveWidth; 
    float y = 0; 
    switch (i % 4) 
    { 
    case 0: 
    case 2: 
     //          
     y = mLevelLine; 
     break; 
    case 1: 
     //          
     y = mLevelLine + mWaveHeight; 
     break; 
    case 3: 
     //          
     y = mLevelLine - mWaveHeight; 
     break; 
    } 
    mPointsList.add(new Point(x, y)); 
   } 
  } 
 } 
 
 @Override 
 protected void onDraw(Canvas canvas) 
 { 
 
  mWavePath.reset(); 
  int i = 0; 
  mWavePath.moveTo(mPointsList.get(0).getX(), mPointsList.get(0).getY()); 
  for (; i < mPointsList.size() - 2; i = i + 2) 
  { 
   mWavePath.quadTo(mPointsList.get(i + 1).getX(), 
     mPointsList.get(i + 1).getY(), mPointsList.get(i + 2) 
       .getX(), mPointsList.get(i + 2).getY()); 
  } 
  mWavePath.lineTo(mPointsList.get(i).getX(), mViewHeight); 
  mWavePath.lineTo(mLeftSide, mViewHeight); 
  mWavePath.close(); 
 
  // mPaint Style FILL,     Path   
  canvas.drawPath(mWavePath, mPaint); 
  //       
  canvas.drawText("" + ((int) ((1 - mLevelLine / mViewHeight) * 100)) 
    + "%", mViewWidth / 2, mLevelLine + mWaveHeight 
    + (mViewHeight - mLevelLine - mWaveHeight) / 2, mTextPaint); 
 } 
 
 class MyTimerTask extends TimerTask 
 { 
  Handler handler; 
 
  public MyTimerTask(Handler handler) 
  { 
   this.handler = handler; 
  } 
 
  @Override 
  public void run() 
  { 
   handler.sendMessage(handler.obtainMessage()); 
  } 
 
 } 
 
 class Point 
 { 
  private float x; 
  private float y; 
 
  public float getX() 
  { 
   return x; 
  } 
 
  public void setX(float x) 
  { 
   this.x = x; 
  } 
 
  public float getY() 
  { 
   return y; 
  } 
 
  public void setY(float y) 
  { 
   this.y = y; 
  } 
 
  public Point(float x, float y) 
  { 
   this.x = x; 
   this.y = y; 
  } 
 
 } 
 
} 
코드 에 주석 이 많이 써 있어 서 이해 하기 어렵 지 않 습 니 다.
데모 레이아웃:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="#000000" > 
 
 <com.jingchen.waveview.WaveView 
  android:layout_width="100dp" 
  android:background="#ffffff" 
  android:layout_height="match_parent" 
  android:layout_centerInParent="true" /> 
 
</RelativeLayout> 
MainActivity 코드:

package com.jingchen.waveview; 
 
import android.os.Bundle; 
import android.app.Activity; 
import android.view.Menu; 
 
public class MainActivity extends Activity 
{ 
 
 @Override 
 protected void onCreate(Bundle savedInstanceState) 
 { 
  super.onCreate(savedInstanceState); 
  setContentView(R.layout.activity_main); 
 } 
 
 @Override 
 public boolean onCreateOptionsMenu(Menu menu) 
 { 
  getMenuInflater().inflate(R.menu.main, menu); 
  return true; 
 } 
 
} 
코드 양 이 적어 서 간단하게 물결 효 과 를 낼 수 있 습 니 다.
원본 다운로드:&lt;안 드 로 이 드:수류 파동 효과 구현&gt;
이상 은 본 고의 모든 내용 입 니 다.여러분 이 안 드 로 이 드 소프트웨어 프로 그래 밍 을 배 우 는 데 도움 이 되 기 를 바 랍 니 다.

좋은 웹페이지 즐겨찾기