Android 사용자 정의 view 물결 무늬 애니메이션 효과 구현

13733 단어 android물결 무늬
실제 개발 에서 상대 적 으로 복잡 한 수 요 를 만 날 때 가 많 습 니 다.예 를 들 어 제품 여동생 종이 나 UI 여동생 종이 가 어디서 사람 을 흥분 시 키 는 효 과 를 보 았 는 지 흥 겹 게 찾 아 왔 습 니 다.본 후에 목적 이 명확 합 니 다.물론 당신 이 그녀 에 게 줄 수 있 기 를 바 랍 니 다.
이런 중요 한 때 에 몸 이 굳 어야 하 는데 절대 안 된다 고 말 하지 마 세 요.남자 가 어떻게 안 된다 고 할 수 있 습 니까?
자,모두 가 여동생 들 이 원 하 는 것 을 줄 수 있 도록 나중에 비교적 좋 은 효 과 를 점차적으로 공유 할 것 입 니 다.목적 은 하나 입 니 다.사용자 정의 view 를 통 해 우리 가 실현 할 수 있 는 동 효 를 실현 하 는 것 입 니 다.
오늘 은 주로 물결 무늬 효과 공유:
1.표준 코사인 물결 무늬;
2.비 표준 원형 액체 기둥 물결 무늬;
비록 모두 물결 무늬 라 고 하지만 이들 은 실현 에 있어 차이 가 비교적 크다.하 나 는 정 코사인 함 수 를 통 해 물결 무늬 효 과 를 모 의 하고 다른 하 나 는 이미지 의 혼합 모델(Porter Duff Xfermode)에 활용 된다.
먼저 효과 보기:   
                                               
사용자 정의 View 는 실제 상황 에 따라 View,TextView,ImageView 또는 다른 것 을 계승 할 수 있 습 니 다.우 리 는 먼저 안 드 로 이 드 를 이용 하여 우리 에 게 좋 은 칼날 을 제공 하여 UI 여동생 종 이 를 만족 시 키 는 방법 만 알 아야 합 니 다.
이번 실현 은 모두 계승 view 를 선택 합 니 다.실현 하 는 과정 에서 우 리 는 다음 과 같은 몇 가지 방법 에 관심 을 가 져 야 합 니 다.
1.onMeasure():컨트롤 의 측정 에 가장 먼저 리 셋 합 니 다.
2.onSizeChanged():onMeasure 뒤에서 리 셋 하면 view 의 넓 은 고등 데 이 터 를 얻 을 수 있 고 가로 세로 화면 전환 시 리 셋 할 수 있 습 니 다.
3.onDraw():진짜 그리 기 부분 은 그 려 진 코드 를 모두 여기에 씁 니 다.
그렇다면 우 리 는 먼저 이 세 가지 방법 을 복사 한 후에 상기 두 가지 효 과 를 실현 한다.
표준 코사인 물결 무늬
이런 물결 무늬 는 구체 적 인 함수 로 구체 적 인 궤적 을 모 의 할 수 있 기 때문에 사고방식 은 기본적으로 다음 과 같다.
1.물결 함수 방정식 확정
2.함수 방정식 에 따라 모든 파문 상의 좌 표를 얻어 낸다.
3.물결 을 평평 하 게 이동 시 켜 물결 위의 점 이 끊임없이 이동 할 것 이다.
4.끊임없이 다시 그리 기,동적 물결 무늬 생 성;
위의 생각 이 있 으 면 우 리 는 한 걸음 한 걸음 실현 한다.
정 여현 함수 방정식 은 다음 과 같다.
y=Asin(wx+b)+h,이 공식 에서 w 는 주기 에 영향 을 주 고 A 는 진폭 에 영향 을 주 며 h 는 y 위치 에 영향 을 주 고 b 는 초상 이다.
위의 방정식 에 따라 자신 이 마음 에 드 는 파문 효 과 를 선택 하고 해당 하 는 매개 변수의 수 치 를 확인한다.
그 다음 에 확 정 된 방정식 에 따라 모든 방정식 의 y 수 치 를 얻 고 모든 y 수 치 를 배열 에 저장 합 니 다.

//      view    
mCycleFactorW = (float) (2 * Math.PI / mTotalWidth); 
//   view          y  
for (int i = 0; i < mTotalWidth; i++) { 
 mYPositions[i] = (float) (STRETCH_FACTOR_A * Math.sin(mCycleFactorW * i) + OFFSET_Y); 
}
   모든 y 값 에 따라 onDraw 에서 다음 코드 를 통 해 두 개의 정적 파문 을 그 릴 수 있 습 니 다.

for (int i = 0; i < mTotalWidth; i++) { 
  //  400           y       ,          ,          ,             
  //          
  canvas.drawLine(i, mTotalHeight - mResetOneYPositions[i] - 400, i, 
    mTotalHeight, 
    mWavePaint); 
  //          
  canvas.drawLine(i, mTotalHeight - mResetTwoYPositions[i] - 400, i, 
    mTotalHeight, 
    mWavePaint); 
 } 
이런 방식 은 수학 안의 세분 법,하나의 파문 과 유사 하 다.만약 에 가로로 하나의 화소 점 단위 로 세분 하면 view 총 너비 의 직선 을 형성 하고 모든 직선의 출발점 과 종점 을 우 리 는 알 수 있다.이 를 바탕 으로 우 리 는 모든 세분 화 된 직선(직선 은 세로)을 순환 적 으로 그 려 야 정태 적 인 물결 무늬 를 형성 할 수 있다.
그 다음 에 우 리 는 물결 무늬 를 움 직 이게 했다.그 전에 한 배열 로 모든 y 값 점 을 저장 했다.두 개의 물결 무늬 가 있 고 두 개의 똑 같은 크기 의 배열 을 이용 하여 두 개의 물결 무늬 의 y 값 데 이 터 를 저장 하고 이 두 배열 의 데 이 터 를 계속 바 꾸 었 다.

private void resetPositonY() { 
 // mXOneOffset                 
 int yOneInterval = mYPositions.length - mXOneOffset; 
 //   System.arraycopy               
 System.arraycopy(mYPositions, mXOneOffset, mResetOneYPositions, 0, yOneInterval); 
 System.arraycopy(mYPositions, 0, mResetOneYPositions, yOneInterval, mXOneOffset); 
 
 int yTwoInterval = mYPositions.length - mXTwoOffset; 
 System.arraycopy(mYPositions, mXTwoOffset, mResetTwoYPositions, 0, 
   yTwoInterval); 
 System.arraycopy(mYPositions, 0, mResetTwoYPositions, yTwoInterval, mXTwoOffset); 
} 
이렇게 되면 이 두 배열 의 데 이 터 를 계속 바 꾸 고 계속 갱신 하면 동적 물결 무늬 를 생 성 할 수 있다.
새로 고침 은 invalidate()또는 post Invaidate()를 호출 할 수 있 습 니 다.후자 가 하위 스 레 드 에서 UI 를 업데이트 할 수 있 는 것 과 차이 가 있 습 니 다.
전체 코드 는 다음 과 같 습 니 다.

public class DynamicWave extends View { 
 //      
 private static final int WAVE_PAINT_COLOR = 0x880000aa; 
 // y = Asin(wx+b)+h 
 private static final float STRETCH_FACTOR_A = 20; 
 private static final int OFFSET_Y = 0; 
 //           
 private static final int TRANSLATE_X_SPEED_ONE = 7; 
 //           
 private static final int TRANSLATE_X_SPEED_TWO = 5; 
 private float mCycleFactorW; 
 private int mTotalWidth, mTotalHeight; 
 private float[] mYPositions; 
 private float[] mResetOneYPositions; 
 private float[] mResetTwoYPositions; 
 private int mXOffsetSpeedOne; 
 private int mXOffsetSpeedTwo; 
 private int mXOneOffset; 
 private int mXTwoOffset; 
 private Paint mWavePaint; 
 private DrawFilter mDrawFilter; 
 public DynamicWave(Context context, AttributeSet attrs) { 
  super(context, attrs); 
  //  dp   px,                   
  mXOffsetSpeedOne = UIUtils.dipToPx(context, TRANSLATE_X_SPEED_ONE); 
  mXOffsetSpeedTwo = UIUtils.dipToPx(context, TRANSLATE_X_SPEED_TWO); 
  //           
  mWavePaint = new Paint(); 
  //        
  mWavePaint.setAntiAlias(true); 
  //         
  mWavePaint.setStyle(Style.FILL); 
  //        
  mWavePaint.setColor(WAVE_PAINT_COLOR); 
  mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); 
 } 
 @Override 
 protected void onDraw(Canvas canvas) { 
  super.onDraw(canvas); 
  //  canvas          
  canvas.setDrawFilter(mDrawFilter); 
  resetPositonY(); 
  for (int i = 0; i < mTotalWidth; i++) { 
   //  400           y       ,          ,          ,             
   //          
   canvas.drawLine(i, mTotalHeight - mResetOneYPositions[i] - 400, i, 
     mTotalHeight, 
     mWavePaint); 
   //          
   canvas.drawLine(i, mTotalHeight - mResetTwoYPositions[i] - 400, i, 
     mTotalHeight, 
     mWavePaint); 
  } 
  //            
  mXOneOffset += mXOffsetSpeedOne; 
  mXTwoOffset += mXOffsetSpeedTwo; 
  //           ,      
  if (mXOneOffset >= mTotalWidth) { 
   mXOneOffset = 0; 
  } 
  if (mXTwoOffset > mTotalWidth) { 
   mXTwoOffset = 0; 
  } 
  //   view  ,        20-30ms  ,      
  postInvalidate(); 
 } 
 private void resetPositonY() { 
  // mXOneOffset                 
  int yOneInterval = mYPositions.length - mXOneOffset; 
  //   System.arraycopy               
  System.arraycopy(mYPositions, mXOneOffset, mResetOneYPositions, 0, yOneInterval); 
  System.arraycopy(mYPositions, 0, mResetOneYPositions, yOneInterval, mXOneOffset); 
  int yTwoInterval = mYPositions.length - mXTwoOffset; 
  System.arraycopy(mYPositions, mXTwoOffset, mResetTwoYPositions, 0, 
    yTwoInterval); 
  System.arraycopy(mYPositions, 0, mResetTwoYPositions, yTwoInterval, mXTwoOffset); 
 } 
 @Override 
 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
  super.onSizeChanged(w, h, oldw, oldh); 
  //    view    
  mTotalWidth = w; 
  mTotalHeight = h; 
  //          y  
  mYPositions = new float[mTotalWidth]; 
  //         y  
  mResetOneYPositions = new float[mTotalWidth]; 
  //         y  
  mResetTwoYPositions = new float[mTotalWidth]; 
  //      view    
  mCycleFactorW = (float) (2 * Math.PI / mTotalWidth); 
  //   view          y  
  for (int i = 0; i < mTotalWidth; i++) { 
   mYPositions[i] = (float) (STRETCH_FACTOR_A * Math.sin(mCycleFactorW * i) + OFFSET_Y); 
  } 
 } 
2.비 표준 원형 액체 기둥 물결 무늬
앞의 파형 은 함수 시 뮬 레이 션 을 사용 합 니 다.이것 은 우리 가 다른 방식 으로 그림 으로 실현 하고 먼저 PS 로 파문 이 아 닌 파문 도 를 사용 합 니 다.

연결 이 긴밀 하기 위해 서 는 머리 와 꼬리 가 비교적 평평 하고 높이 가 일치 합 니 다.
생각:
1.원형 그림 을 마스크 로 파형 도 를 걸 러 내기;
2.물결 무늬 그림,즉 그 려 진 물결 무늬 그림 의 영역,즉 srcRect 를 계속 바 꾸 는 것 입 니 다.
3.주기 가 끝나 면 파문 도의 맨 앞에서 다시 계산한다.
우선 비트 맵 초기 화:

private void initBitmap() { 
  mSrcBitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.wave_2000)) 
    .getBitmap(); 
  mMaskBitmap = ((BitmapDrawable) getResources().getDrawable( 
    R.drawable.circle_500)) 
    .getBitmap(); 
 } 
drawable 로 가 져 오 는 방식 을 사용 하면 전역 에 한 장 만 생 성 되 고 시스템 이 관리 되 며 BitmapFactory.decode()에서 나 오 는 것 은 decode 가 몇 번 에 몇 장 을 생 성 하 는 지 스스로 재 활용 해 야 합 니 다.
그리고 파도 와 마스크 그림 을 그립 니 다.그 릴 때 해당 하 는 혼합 모드 를 설정 합 니 다.

/* 
 *              
 */ 
int sc = canvas.saveLayer(0, 0, mTotalWidth, mTotalHeight, null, Canvas.ALL_SAVE_FLAG); 
//            
mSrcRect.set(mCurrentPosition, 0, mCurrentPosition + mCenterX, mTotalHeight); 
//        
canvas.drawBitmap(mSrcBitmap, mSrcRect, mDestRect, mBitmapPaint); 
//           
mBitmapPaint.setXfermode(mPorterDuffXfermode); 
//       
canvas.drawBitmap(mMaskBitmap, mMaskSrcRect, mMaskDestRect, 
  mBitmapPaint); 
mBitmapPaint.setXfermode(null); 
canvas.restoreToCount(sc); 
동적 파도 효 과 를 형성 하기 위해 서 는 스 레 드 동적 으로 그 릴 파도 의 위 치 를 업데이트 합 니 다.

new Thread() { 
 public void run() { 
  while (true) { 
   //              
   mCurrentPosition += mSpeed; 
   if (mCurrentPosition >= mSrcBitmap.getWidth()) { 
    mCurrentPosition = 0; 
   } 
   try { 
    //          ,    cpu   ,        
    Thread.sleep(30); 
   } catch (InterruptedException e) { 
   } 
 
   postInvalidate(); 
  } 
 
 }; 
}.start(); 
주요 과정 은 상기 와 같 습 니 다.모든 코드 는 다음 과 같 습 니 다.

public class PorterDuffXfermodeView extends View { 
 private static final int WAVE_TRANS_SPEED = 4; 
 private Paint mBitmapPaint, mPicPaint; 
 private int mTotalWidth, mTotalHeight; 
 private int mCenterX, mCenterY; 
 private int mSpeed; 
 private Bitmap mSrcBitmap; 
 private Rect mSrcRect, mDestRect; 
 private PorterDuffXfermode mPorterDuffXfermode; 
 private Bitmap mMaskBitmap; 
 private Rect mMaskSrcRect, mMaskDestRect; 
 private PaintFlagsDrawFilter mDrawFilter; 
 private int mCurrentPosition; 
 public PorterDuffXfermodeView(Context context, AttributeSet attrs) { 
  super(context, attrs); 
  initPaint(); 
  initBitmap(); 
  mPorterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); 
  mSpeed = UIUtils.dipToPx(mContext, WAVE_TRANS_SPEED); 
  mDrawFilter = new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG, Paint.DITHER_FLAG); 
  new Thread() { 
   public void run() { 
    while (true) { 
     //              
     mCurrentPosition += mSpeed; 
     if (mCurrentPosition >= mSrcBitmap.getWidth()) { 
      mCurrentPosition = 0; 
     } 
     try { 
      //          ,    cpu   ,        
      Thread.sleep(30); 
     } catch (InterruptedException e) { 
     } 
     postInvalidate(); 
    } 
   }; 
  }.start(); 
 } 
 @Override 
 protected void onDraw(Canvas canvas) { 
  super.onDraw(canvas); 
  //  canvas       
  canvas.setDrawFilter(mDrawFilter); 
  canvas.drawColor(Color.TRANSPARENT); 
  /* 
   *              
   */ 
  int sc = canvas.saveLayer(0, 0, mTotalWidth, mTotalHeight, null, Canvas.ALL_SAVE_FLAG); 
  //            
  mSrcRect.set(mCurrentPosition, 0, mCurrentPosition + mCenterX, mTotalHeight); 
  //        
  canvas.drawBitmap(mSrcBitmap, mSrcRect, mDestRect, mBitmapPaint); 
  //           
  mBitmapPaint.setXfermode(mPorterDuffXfermode); 
  //       
  canvas.drawBitmap(mMaskBitmap, mMaskSrcRect, mMaskDestRect, 
    mBitmapPaint); 
  mBitmapPaint.setXfermode(null); 
  canvas.restoreToCount(sc); 
 } 
 //    bitmap 
 private void initBitmap() { 
  mSrcBitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.wave_2000)) 
    .getBitmap(); 
  mMaskBitmap = ((BitmapDrawable) getResources().getDrawable( 
    R.drawable.circle_500)) 
    .getBitmap(); 
 } 
 //      paint 
 private void initPaint() { 
  mBitmapPaint = new Paint(); 
  //     
  mBitmapPaint.setDither(true); 
  //        
  mBitmapPaint.setFilterBitmap(true); 
  mPicPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
  mPicPaint.setDither(true); 
  mPicPaint.setColor(Color.RED); 
 } 
 @Override 
 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
  super.onSizeChanged(w, h, oldw, oldh); 
  mTotalWidth = w; 
  mTotalHeight = h; 
  mCenterX = mTotalWidth / 2; 
  mCenterY = mTotalHeight / 2; 
  mSrcRect = new Rect(); 
  mDestRect = new Rect(0, 0, mTotalWidth, mTotalHeight); 
  int maskWidth = mMaskBitmap.getWidth(); 
  int maskHeight = mMaskBitmap.getHeight(); 
  mMaskSrcRect = new Rect(0, 0, maskWidth, maskHeight); 
  mMaskDestRect = new Rect(0, 0, mTotalWidth, mTotalHeight); 
 } 
}
원본 다운로드 주소:http://xiazai.jb51.net/201701/yuanma/androidsbw(jb51.net)
위 에서 말 한 것 은 소 편 이 소개 한 안 드 로 이 드 사용자 정의 view 가 물결 무늬 애니메이션 효 과 를 실현 하 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 메 시 지 를 남 겨 주세요.소 편 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기