Android 는 Surface View 를 이용 하여 비 오 는 날씨 애니메이션 효 과 를 실현 합 니 다.

우선 최종 실현 효과 도:

먼저 빗방울 의 실현 을 분석 해 보 자.
  • 모든 빗방울 은 사실 하나의 선 이 고 canvas.drawLine() 을 통 해 그립 니 다
  • 선(빗방울)의 길이,너비,낙하 속도,투명도 와 위 치 는 모두 일정한 범위 내 에서 무 작위 로 생 성 된다
  • draw 한 번 씩 빗방울 의 위 치 를 바 꾸 고 다시 그리 면 빗방울 의 낙하 효 과 를 실현 할 수 있다.
  • 분석 이 끝나 면 바로 하나의 종 류 를 써 서 View 를 계승 한 다음 에 다시 쓸 수 있 습 니까?효과 그림 의 빗방울 이 떨 어 지 는 속도 가 빠르다 는 것 을 볼 수 있 습 니 다.이 는 프레임 마다onDraw() 한 번 에 다시 그 려 야 한 다 는 것 을 의미 합 니 다.만약 당신 의 onDraw()방법 에 있 는 렌 더 링 코드 가 조금 걸 리 면 ViewonDraw() 방법 이 UI 스 레 드 에 호출 된다 면 그리 기 효과 가 원활 하지 않 고 UI 스 레 드 를 막 을 수도 있 습 니 다.그래서 더욱 원활 한 효 과 를 내 고 UI 스 레 드 를 막 지 않 기 위해 서 는 Surface View 를 사용 합 니 다.
    초 면 Surface View
    SurfaceView 는 View 에서 직접 계승 합 니 다.View 는 UI 스 레 드 에서 그 려 야 합 니 다.SurfaceView 는 View 와 다 릅 니 다.비 UI 스 레 드 에서 그 려 서 인터페이스 에 표시 할 수 있 습 니 다.이것 은 새로 스 레 드 를 열 고 렌 더 링 코드 를 이 스 레 드 에 놓 을 수 있다 는 것 을 의미 합 니 다.
    Surface 는 Z 축 으로 정렬 되 어 있 습 니 다.Surface View 의 Z 축 위 치 는 숙주 Window 보다 작 습 니 다.이것 은 항상 자신 이 있 는 Window 뒤에 있다 는 것 을 의미 합 니 다.뒤에 있 는 이상 어떻게 표시 합 니까?Surface View 는 Window 에'구멍'을 쳤 습 니 다.(사실은 숙주 Window 에 투명 한 영역 을 설정 하여 표시 할 수 있 도록 하 는 것 입 니 다)그의 형제 노드 의 View 가 그것 을 덮어 쓰 는 것 을 의미 합 니 다.예 를 들 어 Surface View 위 에 단추,텍스트 등 컨트롤 을 설치 할 수 있 습 니 다.
    아래 Surface 에 접근 하려 면 Android 를 통 해 Surface Holder 인 터 페 이 스 를 제공 할 수 있 습 니 다.Surface ViewonDraw() 를 호출 하여 얻 을 수 있 습 니 다.
    Surface View 는 라 이 프 사이클 이 있 습 니 다.라 이 프 사이클 동안 그리 기 코드 를 실행 해 야 하기 때문에 Surface View 의 상태(예 를 들 어 생 성 및 소각)를 감청 해 야 합 니 다.여기 Android 는 우리 에 게getHolder() 이 인 터 페 이 스 를 제공 하여 Surface View 의 상 태 를 편리 하 게 감청 할 수 있 습 니 다.
    그럼 아래SurfaceHolder.Callback 인 터 페 이 스 를 보 겠 습 니 다.
    
    public interface Callback {
    
    // SurfaceView      (SurfaceView      )
     public void surfaceCreated(SurfaceHolder holder);
    
    // SurfaceView       
     public void surfaceChanged(SurfaceHolder holder, int format, int width,
     int height);
    
    // SurfaceView      (SurfaceView       )
     public void surfaceDestroyed(SurfaceHolder holder);
    
     }
    우리 의 그리 기 코드 는 surfaceCreated 와 surfaceDestroyed 사이 에서 실행 되 어야 합 니 다.그렇지 않 으 면 잘못 되 었 습 니 다.SurfaceHolder.Callback 의 리 셋 방법 은 UI 스 레 드 에서 실 행 됩 니 다.스 레 드 를 그 리 려 면 우리 가 수 동 으로 만들어 야 합 니 다.
    구체 적 으로 는 공식 문 서 를 볼 수 있다.https://developer.android.google.cn/reference/android/view/SurfaceView.html
    View 와 Surface View 의 사용 장면
  • View 는 사용자 와 상호작용 을 하고 렌 더 링 시간 이 길지 않 은 컨트롤 에 적합 합 니 다.View 의 그리 기와 사용자 의 상호작용 이 모두 UI 스 레 드 에 있 기 때 문 입 니 다.
  • Surface View 는 신속 한 업데이트 인터페이스 나 렌 더 링 시간 이 길 어서 사용자 체험 에 영향 을 주 는 장면 에 적합 하 다.
  • SurfaceView 사용(구현)
    여기 서 저 희 는 사용자 정의 View 와 유사 합 니 다.Dynamic WeatherView 를 써 서 Surface View 의 상 태 를 계승 한 다음 에 Surface View 의 상 태 를 감청 하기 위해 서SurfaceHolder.Callback인 터 페 이 스 를 실현 하여 Surface View 의 상 태 를 감청 해 야 합 니 다.인터페이스의 리 셋 구체 적 인 시기 에 도 소개 되 었 습 니 다.
    
    public class DynamicWeatherView extends SurfaceView implements SurfaceHolder.Callback{
    
     public DynamicWeatherView(Context context) {
     this(context, null);
     }
    
     public DynamicWeatherView(Context context, AttributeSet attrs) {
     this(context, attrs, 0);
     }
    
     public DynamicWeatherView(Context context, AttributeSet attrs, int defStyleAttr) {
     super(context, attrs, defStyleAttr);
     }
    
     // SurfaceView      (  )
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
    
     }
    
     // SurfaceView      (   )
     @Override
     public void surfaceDestroyed(SurfaceHolder holder) {
    
     }
    
     @Override
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
     }
    
    }
    위 에서 언급 한 바 와 같이 Surface 를 제어 하려 면 Surface Holder 대상 이 필요 합 니 다.Surface ViewSurfaceHolder.Callback 를 호출 하면 얻 을 수 있 습 니 다.그리고 이 Surface Holder 에 getHolder() 리 셋 을 추가 합 니 다.여기 가 바로 Dynamic WeatherView 현재 대상 입 니 다.
    
    private SurfaceHolder mHolder;
    
    mHolder = getHolder();
    mHolder.addCallback(this);
    mHolder.setFormat(PixelFormat.TRANSPARENT);
    그리고 우리 의 그리 기 라인 을 실현 합 니 다.
    
    private class DrawThread extends Thread {
    
     //          
     private boolean isRunning = false;
    
     public void setRunning(boolean running) {
     isRunning = running;
     }
    
     @Override
     public void run() {
     Canvas canvas;
     //       
     while (isRunning) {
     if (mType != null && mViewWidth != 0 && mViewHeight != 0) {
     canvas = mHolder.lockCanvas();
     if (canvas != null) {
     mType.onDraw(canvas);
     if (isRunning) {
     mHolder.unlockCanvasAndPost(canvas);
     } else {
     //     
     break;
     }
     SystemClock.sleep(1);
     }
     }
     }
     }
    }
    위의 코드 를 통 해 알 수 있 듯 이 Surface View 의 업데이트 절 차 는 구체 적 으로 다음 과 같다.
    
    //         canvas
    canvas = mHolder.lockCanvas();
    //   canvas      
    mType.onDraw(canvas);
    //          
    mHolder.unlockCanvasAndPost(canvas);
    스 레 드 코드 를 그 리 는 양 이 많 지 않 습 니 다.구체 적 인 그리 기 코드 는SurfaceHolder.Callback 에서 mType 은 우리 가 정의 하 는 인터페이스 로 날씨 유형 을 대표 합 니 다.
    
    public interface WeatherType {
     void onDraw(Canvas canvas);
    
     void onSizeChanged(Context context, int w, int h);
    }
    이렇게 서로 다른 날씨 유형 을 실현 하려 면 이 인터페이스 에서 onDraw 와 onSize Changed 방법 을 다시 쓰 면 됩 니 다.여기 서 우 리 는 비가 오 는 효 과 를 실현 하기 때문에 RainTypeImpl 류 를 실현 합 니 다.
    
    public class RainTypeImpl extends BaseType {
    
     //   
     private Drawable mBackground;
     //     
     private ArrayList<RainHolder> mRains;
     //   
     private Paint mPaint;
    
     public RainTypeImpl(Context context, DynamicWeatherView dynamicWeatherView) {
     super(context, dynamicWeatherView);
     init();
     }
    
     private void init() {
     mPaint = new Paint();
     mPaint.setAntiAlias(true);
     mPaint.setColor(Color.WHITE);
     //           3
     mPaint.setStrokeWidth(3);
     mRains = new ArrayList<>();
     }
    
     @Override
     public void generate() {
     mBackground = getContext().getResources().getDrawable(R.drawable.rain_sky_night);
     mBackground.setBounds(0, 0, getWidth(), getHeight());
     for (int i = 0; i < 60; i++) {
     RainHolder rain = new RainHolder(
     getRandom(1, getWidth()),
     getRandom(1, getHeight()),
     getRandom(dp2px(9), dp2px(15)),
     getRandom(dp2px(5), dp2px(9)),
     getRandom(20, 100)
     );
     mRains.add(rain);
     }
     }
    
     private RainHolder r;
    
     @Override
     public void onDraw(Canvas canvas) {
     clearCanvas(canvas);
     //    
     mBackground.draw(canvas);
     //         
     for (int i = 0; i < mRains.size(); i++) {
     r = mRains.get(i);
     mPaint.setAlpha(r.a);
     canvas.drawLine(r.x, r.y, r.x, r.y + r.l, mPaint);
     }
     //               
     for (int i = 0; i < mRains.size(); i++) {
     r = mRains.get(i);
     r.y += r.s;
     if (r.y > getHeight()) {
     r.y = -r.l;
     }
     }
     }
    
     private class RainHolder {
     /**
     *    x    
     */
     int x;
     /**
     *    y    
     */
     int y;
     /**
     *     
     */
     int l;
     /**
     *       
     */
     int s;
     /**
     *      
     */
     int a;
    
     public RainHolder(int x, int y, int l, int s, int a) {
     this.x = x;
     this.y = y;
     this.l = l;
     this.s = s;
     this.a = a;
     }
    
     }
    
    }
    코드 는 어렵 지 않 습 니 다.기본적으로 주석 이 있 습 니 다.Rain Holder 대상 은 빗방울 을 대표 합 니 다.한 번 그 릴 때마다 빗방울 의 위 치 를 바 꾸 고 다음 에 그 릴 준 비 를 해서 빗방울 의 이동 을 실현 합 니 다.
    BaseType 류 는 우리 의 추상 적 인 기류 로mType.onDraw(canvas)인 터 페 이 스 를 실 현 했 고 내부 에 일부 공공 방법 이 있 으 며 구체 적 으로 Demo 의 코드 를 볼 수 있다.
    마지막 으로 우리 의 Activity 코드:
    
    public class MainActivity extends Activity {
    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     DynamicWeatherView mDynamicWeatherView = (DynamicWeatherView) findViewById(R.id.dynamic_weather_view);
     mDynamicWeatherView.setType(new RainTypeImpl(this, mDynamicWeatherView));
     }
    }
    앞으로 서로 다른 날씨 유형 을 구현 하려 면 베이스 타 입 클래스 를 계승 해 재 작성 하 는 방법 만 있 으 면 된다.
    원본 다운로드:여 기 를 클릭 하 세 요.
    총결산
    이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 안 드 로 이 드 개발 자 들 에 게 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기