Android 동적 가우스 퍼 지 효과 튜 토리 얼

앞 에 쓰다
최근 에 필 설 프로젝트 의 준 비 를 계속 하고 있 는데 모호 한 효 과 를 사용 해 야 할 수도 있다 는 것 을 고려 하여 고 스 모호 효과 의 실현 을 배 웠 다.비교적 유명한 것 은 바로 FastBlur 와 그 파생 된 최적화 방안,그리고 오늘 말 하고 자 하 는 RenderScript 이다.
이 물건 은 지금 필요 해서 배 우 는 것 이기 때문에 이미지 처리 와 렌 더 링 문 제 는 언급 하지 않 겠 습 니 다.그러나 사용 하 는 과정 에서 서로 다른 방안 이 똑 같은 모호 효 과 를 실현 할 수 있 지만 효율 의 차 이 는 정말 크다 는 것 을 느 낄 수 있다.
이 글 에서 실 현 된 고 스 모호 함 은 아래 의 이 글 에 근거 하여 배 운 것 이 므 로 먼저 추천 합 니 다.본 논문 의 내용 과 내용 은 차이 가 많 지 않 고 조금 상세 하 게 말 했 을 뿐 코드 중의 일부 가 논리 적 이 고 세부 적 인 처 리 를 실현 하도록 수정 했다.그러나 주 체 는 내용 이 변 하지 않 기 때문에 어떤 문장 을 선택해 서 배 워 도 마찬가지다.
이런 고 스 퍼 지 효 과 를 어떻게 실현 하 는 지 살 펴 보 자.

간단하게 얘 기 하 자.Renderscript.
효과 의 실현 은 Renderscript 에 기반 한 것 이기 때문에 먼저 알 아 볼 필요 가 있 습 니 다.
그것 의 공식 문 서 를 보면 매우 현묘 하 게 말한다.우 리 는 조금 만 알 았 으 면 좋 겠 다.
RenderScript is a framework for running computationally intensive tasks at high performance on Android.
렌 더 스 크 립 트 는 안 드 로 이 드 플랫폼 에서 고성능 컴 퓨 팅 을 하 는 프레임 워 크 다.
고성능 컴 퓨 팅 인 만큼 렌 더 스 크 립 트 는 이미지 에 대한 처리 가 매우 강하 기 때문에 이 를 통 해 고 스 퍼 지 를 실현 하 는 것 이 좋 습 니 다.
그럼 어떻게 사용 하나 요?공식 문서 에서 볼 수 있 듯 이 자바 코드 에서 Renderscript 을 사용 하려 면 android.renderscript 또는 android.support.v8.renderscript 의 API 에 의존 해 야 합 니 다.API 가 있 으 니까 훨씬 쉬 워 요.
다음은 사용 절 차 를 간단하게 말씀 드 리 겠 습 니 다.이것 도 공식 문서 의 설명 입 니 다.
  • 먼저 Context 를 통 해 Renderscript 을 만들어 야 합 니 다
  • 그 다음 에 만 든 Renderscript 을 통 해 자신 이 필요 로 하 는 스 크 립 트(ScriptIntrinsic)를 만 듭 니 다.예 를 들 어 여기 가 모호 해 야 합 니 다.그것 이 바로 ScriptIntrinsicBlur 입 니 다
  • 그리고 적어도 하나의 Allocation 류 를 만들어 메모리 공간 을 만 들 고 분배 합 니 다
  • 4.567917.그 다음 에 이미지 에 대해 처리 하 는 것 이다.예 를 들 어 모호 처리 등 이다
  • 처리 가 끝 난 후에 방금 알 로 케 이 션 류 가 분 배 된 메모리 공간 을 채 워 야 합 니 다
  • 4.567917.마지막 으로 일부 자원 을 선택적으로 회수 할 수 있다.
    문서 의 해석 은 영원히 규칙 적 이 고 이해 하기 어렵다.우 리 는 원래 의 블 로 거 추 수의 긴 코드 와 결합 하여 절 차 를 살 펴 보 자.
    
    /**
     * @author Qiushui
     * @description        
     * @revision Xiarui 16.09.05
     */
    public class BlurBitmapUtil {
      //      
      private static final float BITMAP_SCALE = 0.4f;
    
      /**
       *          
       *
       * @param context      
       * @param image         
       * @return         
       */
      public static Bitmap blurBitmap(Context context, Bitmap image,float blurRadius) {
        //           
        int width = Math.round(image.getWidth() * BITMAP_SCALE);
        int height = Math.round(image.getHeight() * BITMAP_SCALE);
    
        //                
        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
        //             
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
    
        //   RenderScript    
        RenderScript rs = RenderScript.create(context);
        //          RenderScript     
        ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
    
        //   RenderScript     VM     ,      Allocation           
        //   Allocation            ,    copyTo()       
        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
    
        //          , 25f      
        blurScript.setRadius(blurRadius);
        //   blurScript       
        blurScript.setInput(tmpIn);
        //              
        blurScript.forEach(tmpOut);
    
        //       Allocation 
        tmpOut.copyTo(outputBitmap);
    
        return outputBitmap;
      }
    }
    
    
    위 에 고 스 의 모호 한 코드 를 처리 하 는 것 입 니 다.그 중에서 주석 은 매우 상세 하 게 쓰 여 있 고 그림 의 크기 를 조정 하여 처리 하 였 습 니 다.방금 말 한 절 차 를 결합 하면 여러분 은 대략적인 인상 을 가 질 수 있 을 것 입 니 다.정말 모 르 더 라 도 괜 찮 습 니 다.이것 은 도구 류 입 니 다.직접 복사 하면 됩 니 다.
    물론 원 블 로 거 는 코드 를 바퀴 로 봉 했 고 프로젝트 에서 Gradle 을 직접 인용 할 수도 있 지만 소스 코드 는 봐 야 한다 고 생각 합 니 다.
    단순 모호
    자,대충 기억 이 나 면 고 스 의 모호 한 효 과 를 어떻게 실현 하 는 지 살 펴 보 자!
    우선 프로젝트 에서 원 블 로 거 가 봉 인 된 바퀴 를 직접 인용 할 수 있 습 니 다.
    compile 'com.qiushui:blurredview:0.8.1'
    인용 하지 않 으 려 면 현재 Module 의 build.gradle 에 다음 코드 를 추가 해 야 합 니 다.
    
    defaultConfig {
      renderscriptTargetApi 19
      renderscriptSupportModeEnabled true
    }
    
    구축 되면 사용 할 수 있 습 니 다.빌 드 에 실패 하면 minSdkVersion 을 19 로 설정 하면 됩 니 다.어떤 이유 인지 모 르 겠 습 니 다.그러나 StackOverflow 에서 이것 이 bug 라 는 것 을 알 게 되 었 다 면 깊이 연구 할 필요 가 없다.
    지금 보면 코드 가 실 현 됩 니 다.먼저 레이아웃 파일 에 ImageView 가 있 습 니 다.할 말 이 없습니다.위의 퍼 지 이미지 도구 류 를 통 해 알 수 있 듯 이 고 스 퍼 지 효 과 를 가 진 그림 을 얻 으 려 면 세 가지 가 필요 합 니 다.
    문맥:문맥 대상
    Bitmap:흐릿 한 그림 이 필요 합 니 다.
    BlurRadius:퍼 지 정도
    여 기 는 주의해 야 한다.
    현재 이 방안 은 PNG 형식의 그림 에 만 적용 되 며,그림 크기 는 좀 작 게 하 는 것 이 좋 습 니 다.코드 에 그림 이 축소 되 었 지만,여전히 멈 출 수 있 습 니 다.
    이제 그림 과 퍼 지 정도 만 설정 하면 됩 니 다.
    
    /**
     *    View
     */
    @SuppressWarnings("deprecation")
    private void initView() {
      basicImage = (ImageView) findViewById(R.id.iv_basic_pic);
      //     
      Bitmap initBitmap = BitmapUtil.drawableToBitmap(getResources().getDrawable(R.raw.pic));
      //          
      Bitmap blurBitmap = BlurBitmapUtil.blurBitmap(this, initBitmap, 20f);
      basicImage.setImageBitmap(blurBitmap);
    }
    
    실행 도 보기:

    이 를 통 해 알 수 있 듯 이 그림 은 모호 효 과 를 실 현 했 고 속도 도 매우 빠르다.전체적으로 BlurBitmapUtil.blurBitmap()를 통 해 모호 효 과 를 얻 을 수 있 는 그림 이다.
    사용자 정의 퍼 지 컨트롤
    원래 블 로 거들 의 바퀴 에는 사용자 정의 Blurred View 가 들 어 있 었 는데 처음에는 사용자 정의 가 필요 없다 고 생각 했 습 니 다.사용자 정의 원인 은 동적 모호 효 과 를 실현 해 야 한 다 는 것 을 발견 했다.
    그런데 왜 모호 도 를 수 동 으로 설정 할 수 없 습 니까?그 가 내 놓 은 설명 은:
    "위의 코드 를 사용 하여 실시 간 으로 렌 더 링 을 하면 인터페이스 가 심각하게 걸 릴 수 있 습 니 다."
    나 도 직접 해 봤 는데,확실히 좀 끊 긴 다.그 가 동적 모호 처 리 를 실현 하 는 방안 은 이렇다.
    이 어"그림 을 최대한 흐 리 게 처리 한 다음,희미 해진 그림 위 에 원 도 를 올 려 놓 고,원 도의 투명도(Alpha 값)를 끊임없이 바 꾸 어 동적 모호 효 과 를 구현 한다"고 덧 붙 였 다.
    이 방안 은 확실히 동적 효 과 를 교묘 하 게 실현 하지만 이런 방식 을 사용 하려 면 반드시 두 장의 똑 같은 그림 이 있어 야 한 다 는 것 을 주의해 야 한다.코드 에 직접 쓰 려 면 두 개의 컨트롤 이 필요 하 다.그림 이 많 으 면 분명 바람 직 하지 않다.그래서 바퀴 안에 사용자 정의 Blurred View 가 있 습 니 다.
    그러나 이 Blurred View 는 잘 봉 인 된 것 이 아니 라 일부 내용 을 삭 제 했 습 니 다.이 유 는 잠시 후에 다시 이야기 하 겠 습 니 다.핵심 코드 부터 살 펴 보 겠 습 니 다.
    먼저 사용자 정의 BlurredView 가 RelativeLayout 에 계승 되 었 습 니 다.레이아웃 파일 에서 볼 수 있 습 니 다.그 안에 두 개의 ImageView 가 있 고 겹 쳐 있 습 니 다.
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
    
      <ImageView
        android:id="@+id/blurredview_blurred_img"
        .../>
    
      <ImageView
        android:id="@+id/blurredview_origin_img"
        .../>
    
    </FrameLayout>
    
    
    동시에 일부 속성 도 정의 했다.
    
    <resources>
      <declare-styleable name="BlurredView">
        <attr name="src" format="reference"/>
        <attr name="disableBlurred" format="boolean"/>
      </declare-styleable>
    </resources>
    
    하 나 는 그림 을 설정 하 는 것 이 고,하 나 는 모호 함 을 사용 하지 않 을 지 설정 하 는 것 입 니 다.마지막 으로 BlurredView 류 입 니 다.코드 는 다음 과 같 습 니 다.대량의 삭제 가 있 고 핵심 코드 만 붙 입 니 다.
    
    /**
     * @author Qiushui
     * @description      View 
     * @revision Xiarui 16.09.05
     */
    public class BlurredView extends RelativeLayout {
    
      /*==========      ==========*/
      private Context mContext;//     
      private static final int ALPHA_MAX_VALUE = 255;//     
      private static final float BLUR_RADIUS = 25f;//     ( 0.0 25.0  )
    
      /*==========      ==========*/
      private ImageView mOriginImg;//  ImageView
      private ImageView mBlurredImg;//    ImageView
      private Bitmap mBlurredBitmap;//    Bitmap
      private Bitmap mOriginBitmap;//  Bitmap
    
      /*==========      ==========*/
      private boolean isDisableBlurred;//        
    
      ...
    
      /**
       *               
       *
       * @param blurredBitmap       
       */
      public void setBlurredImg(Bitmap blurredBitmap) {
        if (null != blurredBitmap) {
          mOriginBitmap = blurredBitmap;
          mBlurredBitmap = BlurBitmapUtil.blurBitmap(mContext, blurredBitmap, BLUR_RADIUS);
          setImageView();
        }
      }
      ...
    
      /**
       *   ImageView
       */
      private void setImageView() {
        mBlurredImg.setImageBitmap(mBlurredBitmap);
        mOriginImg.setImageBitmap(mOriginBitmap);
      }
    
      /**
       *       
       *
       * @param level     ,     0~100   .
       */
      @SuppressWarnings("deprecation")
      public void setBlurredLevel(int level) {
        //              
        if (level < 0 || level > 100) {
          throw new IllegalStateException("No validate level, the value must be 0~100");
        }
    
        //        
        if (isDisableBlurred) {
          return;
        }
    
        //     
        mOriginImg.setAlpha((int) (ALPHA_MAX_VALUE - level * 2.55));
      }
    
      ...
    }
    
    
    코드 에서 볼 수 있 듯 이 가장 핵심 적 인 것 은 다음 과 같은 세 가지 방법 이다.
    setBlurredImg(Bitmap blurredBitmap):그림 을 설정 하고 두 부 복사 합 니 다.
    setImageView():두 개의 ImageView 에 해당 하 는 그림 을 설정 하고 내부 호출 합 니 다.
    setBlurredLevel(int level):투명 도 를 설정 합 니 다.
    사고방식 은 먼저 그림 한 장 을 선택 하고,한 장 은 원화 로 하고,한 장 은 모호 하 게 처 리 된 그림 으로 하 는 것 이다.이 두 장의 그림 을 사용자 정의 BlurredView 의 두 개의 ImageView 에 각각 설정 하고 모호 한 그림 의 투명 도 를 처리 합 니 다.
    자,이제 사용자 정의 퍼 지 효과 도 를 쓰 겠 습 니 다.먼저 레이아웃 입 니 다.간단 합 니 다.
    
     <com.blurdemo.view.BlurredView
        android:id="@+id/bv_custom_blur"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:src="@raw/pic"
        app:disableBlurred="false" />
    이 를 통 해 알 수 있 듯 이 그림 을 설정 하고 오픈 퍼 지 를 설정 합 니 다.그러면 저 희 는 Activity 에서 투명 정도 만 설정 하면 됩 니 다.
    
    private void initView() {
        customBView = (BlurredView) findViewById(R.id.bv_custom_blur);
        //     
        customBView.setBlurredLevel(100);
      }
    
    효과 도 는 위의 그림 과 마찬가지 로 중복 붙 이지 않 습 니 다.이 를 통 해 알 수 있 듯 이 코드 는 매우 간단 하지만 편리 하고 간단 하기 때문에 사용자 정의 View 의 역할 이 아니 라 다음 에 말 할 동적 모호 효과 의 실현 에 작용 한다.
    동적 모호
    우 리 는 먼저 동적 모호 효과 가 무엇 인지 살 펴 보 자.

    그림 에서 볼 수 있 듯 이 우리 가 화면 을 만 질 때 배경의 모호 정도 가 달라 진다.퍼 지 정도 와 그 카드 를 직접 설정 하려 면 원 블 로 거들 의 말대 로 두 장의 그림 으로 이 루어 질 수 있다.
    대체적인 사고방식 은 위의 그림 을 모호 하 게 처리 하고 아래 의 그림 을 처리 하지 않 은 다음 에 손짓 을 통 해 위의 모호 한 그림 의 투명 도 를 바 꾸 면 된다 는 것 이다.
    그래서 앞의 코드 와 거의 같 습 니 다.onTouch Event 방법 을 다시 쓰 면 됩 니 다.
    
    /**
     *    View
     */
    private void initView() {
      customBView = (BlurredView) findViewById(R.id.bv_dynamic_blur);
      //       
      initLevel = 100;
      customBView.setBlurredLevel(initLevel);
    }
    
    /**
     *     
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
      switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
          downY = ev.getY();
          break;
    
        case MotionEvent.ACTION_MOVE:
          float moveY = ev.getY();
          //      
          float offsetY = moveY - downY;
          //                
          int screenY = getWindowManager().getDefaultDisplay().getHeight() * 10;
          //             
          movePercent = offsetY / screenY;
          currentLevel = initLevel + (int) (movePercent * 100);
          if (currentLevel < 0) {
            currentLevel = 0;
          }
          if (currentLevel > 100) {
            currentLevel = 100;
          }
          //     
          customBView.setBlurredLevel(currentLevel);
          //        
          initLevel = currentLevel;
          break;
        case MotionEvent.ACTION_UP:
          break;
      }
      return super.onTouchEvent(ev);
    }
    
    
    코드 에서 볼 수 있 듯 이 여 기 는 손가락 미끄럼 거리 가 화면의 백분율 을 차지 하여 변 경 된 투명 등급 을 계산 하 는 것 으로 코드 가 어렵 지 않 고 쉽게 이해 할 수 있 습 니 다.물론 원 블 로 거 블 로 그 는 진도 조 를 통 해 바 뀌 었 고 괜 찮 았 으 니 군말 하지 않 겠 다.
    RecylcerView 와 결합
    먼저 효과 도 를 살 펴 보면 이 그림 도 원래 블 로 거들 을 본 떠 서 이 루어 진 것 이지 만 약간 다르다.

    원래 사용자 정의 BlurredView 에는 배경 그림 의 위 치 를 바 꾸 는 코드 도 몇 개 있 습 니 다.위 에서 아래로 끌 어 내 릴 때 배경 그림 도 이동 할 수 있 기 를 바 랍 니 다.그러나 체험 적 으로 효과 가 좋 지 않 고 위로 끌 어 올 리 는 과정 에서 여백 을 남 기 는 문제 가 발생 할 수 있 습 니 다.
    원 블 로 거 는 배경 그림 에 수 동 으로 높이 를 올 리 는 방안 을 제 시 했 지만 이것 은 가장 좋 은 해결 방식 이 아니 었 다.그래서 나 는 이 기능 을 삭제 하고 더 좋 은 실현 방식 을 찾 아 보충 했다.
    이제 와 서 어떻게 실현 할 것 인가?먼저 레이아웃 은 바로 아래 층 에서 사용자 정의 BlurredView 입 니 다.위 에 있 는 RecylcerView,RecylcerView 는 두 개의 Type 이 있 습 니 다.하 나 는 머리 레이아웃 이 고 하 나 는 아래 목록 입 니 다.간단 합 니 다.상세 하 게 말 하지 않 겠 습 니 다.
    중점 은 여전히 동적 모호 의 실현 이다.위의 동적 모호 에서 우 리 는 onTouch Event 를 다시 쓰 는 방법 을 취 했다.그러나 여 기 는 바로 RecylcerView 이다.우 리 는 그의 스크롤 감청,즉 onScroll Listener 에 따라 동적 투명 도 를 바 꿀 수 있다.핵심 방법 은 다음 과 같다.
    
     //RecyclerView     
      mainRView.setOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
          super.onScrollStateChanged(recyclerView, newState);
        }
    
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
          super.onScrolled(recyclerView, dx, dy);
          //    
          mScrollerY += dy;
          //                         
          if (Math.abs(mScrollerY) > 1000) {
            mAlpha = 100;
          } else {
            mAlpha = Math.abs(mScrollerY) / 10;
          }
          //       
          recyclerBView.setBlurredLevel(mAlpha);
        }
      });
    
    
    코드 는 매우 간단 합 니 다.바로 onScrolled 방법 에서 투명 도 를 계산 하고 동적 으로 바 꾸 는 것 입 니 다.원 리 를 파악 하면 실현 하기 가 쉽 습 니 다.
    총결산
    앞의 모든 동적 그림 을 보면 운행 이 비교적 빠 르 지만 저 는 Android Monitor 에서 보 았 습 니 다.처음에 퍼 지 기 를 시 작 했 을 때 GPU 가 렌 더 링 하 는 시간 이 길 기 때문에 성능 이 좋 지 않 을 수 있 습 니 다.

    물론 시 뮬 레이 터 와 관련 이 있 을 수도 있 고,실제 테스트 는 매우 빠르다.그리고 FastBlur 보다 빠 른 것 같 습 니 다.고 스 퍼 지 실현 방법의 성능 을 시험 해 볼 시간 이 있 으 면 비교 해 보 세 요.
    여기까지 고 스 의 모호 함 을 실현 하 는 이런 방법 은 이미 모두 말 했 습 니 다.원 블 로 거들 의 이렇게 우수한 글 에 감 사 드 리 고 다시 링크 를 첨부 합 니 다.
    추 수장 천 C 는 1 분 동안 동적 모호 효 과 를 실현 하 는 것 을 가르쳐 준다.
    기타 참고 자료
    RenderScript C Android Developers
    Android RenderScript 입문(1)
    가우스 퍼 지 효과 실현 방안 및 성능 대비 C lcyFox
    프로젝트 원본 코드
    BlurDemo C IamXiaRui C Github
    이상 은 안 드 로 이 드 동적 고 스 퍼 지 효과 튜 토리 얼 에 대한 예 입 니 다.본 사이트 에 대한 지지 에 감 사 드 립 니 다!

    좋은 웹페이지 즐겨찾기