Android 사용자 정의 View 회전 하 는 원형 그림 구현

사용자 정의 View 는 안 드 로 이 드 가 개발 한 중요 한 기능 입 니 다.안 드 로 이 드 가 제공 하 는 2/3D 로 관련 종 류 를 그리 면 매우 멋 진 효 과 를 실현 할 수 있 고 확실한 프로 그래 밍 기반 이 필요 합 니 다.
하지만 사용자 정의 뷰 는 또 나의 약점 이기 때문에 최근 에는 사용자 정의 뷰 를 모색 하고 연습 하고 있다.오늘 나 는 원형 그림 을 쓰 고 고 르 게 회전 하 는 Rotate Circle ImageView 를 썼 다.실현 방법 은 스스로 생각 하 는 것 이지 만,틀림없이 가장 좋 은 실현 방법 은 아 닐 것 이다.
사용자 정의 View 는 4 단계 로 나 뉜 다.
1:사용자 정의 속성;
2.사용자 정의 View 를 만 들 고 구조 방법 에서 사용자 정의 속성 을 가 져 옵 니 다.
3.onMeasure 방법 다시 쓰기;
4:onDraw 재 작성 방법
먼저 효과 도 를 보 여 드릴 게 요.

res/values/아래 새 attrs.xml
사용자 정의 속성

<declare-styleable name="RotateCircleImageView"> 
    <attr name="image" format="reference" /> 
    <attr name="rotate_sd" format="float" /> 
    <attr name="rotate_fx" format="integer" /> 
    <attr name="isRotate" format="boolean" /> 
    <attr name="circle_back_width" format="dimension" /> 
    <attr name="circle_back_color" format="color" /> 
  </declare-styleable> 
RotateCircleImageView 만 들 기

public RotateCircleImageView(Context context) { 
    this(context, null); 
  } 
 
  public RotateCircleImageView(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
  } 
 
  public RotateCircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    initData(); 
  } 
View 의 세 가지 구조 함 수 를 다시 쓰 고 한 개의 인삼 으로 두 개의 인삼 을 호출 하 며 두 개의 인삼 으로 세 개의 인삼 을 호출 합 니 다.삼 삼 의 구조 에서 파 라 메 터 를 초기 화 합 니 다.

private Bitmap image; 
private Bitmap tempImage; 
private Paint paint; 
private int bkWidth;//         
private int rotate_fx=0;//     0=    1=    
private float rotateSD = 0.8f;//       --    0.1f-1,      
private boolean isRotate = false;//       
 private void initData() { 
    paint = new Paint(); 
    paint.setAntiAlias(true); 
    paint.setDither(true); 
    TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, 
        R.styleable.RotateCircleImageView, defStyleAttr, 0);//             

    paint.setColor(typedArray.getColor(R.styleable.RotateCircleImageView_circle_back_color, 
        Color.BLACK)); 
    tempImage = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId( 
        R.styleable.RotateCircleImageView_image, R.mipmap.ic_launcher)); 
    bkWidth = typedArray.getDimensionPixelSize(R.styleable. 
            RotateCircleImageView_circle_back_width, 
        DensityUtils.dp2px(context, 100));//       ,DensityUtils        , dp   px  

    rotateSD = typedArray.getFloat(R.styleable.RotateCircleImageView_rotate_sd, 0.8f); 
    rotate_fx = typedArray.getInt(R.styleable.RotateCircleImageView_rotate_fx, 0); 
    isRotate = typedArray.getBoolean(R.styleable.RotateCircleImageView_isRotate, true); 
} 
재 작성 측정 방법:주로 소포 내용 의 너비 와 높이 를 측정 하 는 값 입 니 다.

@Override 
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
    int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
    int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);//               
    int mWidth;//     
    int mHeight;//     
    int yy_width = widthSize;//    ,                
    if (widthMode == MeasureSpec.EXACTLY) { 
      mWidth = widthSize;//            (          ),         
 
    } else { 
      yy_width=tempImage.getWidth();//       ,            
      mWidth = yy_width + getPaddingLeft() + getPaddingRight();//              Padding   
    } 
    if (heightMode == MeasureSpec.EXACTLY) { 
      mHeight = heightSize;//   
    } else { 
      mHeight = getPaddingTop() + getPaddingBottom() + yy_width;//              Padding   
                   //           , Padding           ,     padding 
 } 
    if (tempImage.getHeight() < tempImage.getWidth()) { 
    //   Bitmap                  ,          ,      
      image = Bitmap.createScaledBitmap(tempImage, yy_width - bkWidth, 
          yy_width - bkWidth, false); 
    } else { 
      
    //   Bitmap                  (         ,       ) 
    //                ,                 
      image = Bitmap.createScaledBitmap(tempImage, yy_width - bkWidth,(int) (tempImage.getHeight() / 
      (((float) tempImage.getWidth()) / yy_width) - bkWidth), false); 
    } 
  setMeasuredDimension(mWidth, mHeight);//  View   ,     
  } 
만약 너비 가 지정 한 크기 라면 높이 를 이 크기 에 따라 비례 하여 크기 를 조정 하고 싶 습 니 다.그러면 그림 의 원본 크기 를 가 져 와 야 하기 때문에 tempImage 가 필요 합 니 다.왜 임시 Bitmap 을 씁 니까?왜냐하면 제 가 테스트 를 해 봤 는데...   만약 내 가 이 이미지 로 Bitmap.createcaledBitmap(image,xx,xx,false)를 직접 사용한다 면;의 반환 값 을 image 에 부여 하면 이 코드 앞에서 image.getWidth()와 Image.getHeight()를 사용 하 더 라 도 되 돌아 오 는 값 은 원본 크기 가 아 닌 크기 로 크기 를 조정 하 는 것 이 이상 합 니 다.혹시 BItmap 의 getWidth 와 getHeight 는 비동기 인가요?아 는 사람 이 풀 어 줬 으 면 좋 겠 어 요.
마지막 으로 onDraw 다시 쓰 는 방법.

@Override 
  protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
 
    canvas.drawCircle(getWidth() / 2, getWidth() / 2 , getWidth() / 2, paint);//      
    canvas.drawBitmap(getCircleBitmap(image, image.getWidth(), rotateSD), 
        getWidth() / 2 - image.getWidth() / 2, 
        getHeight() / 2 - image.getWidth() / 2, paint);//       
    if (isRotate) { 
      handler.postDelayed(runnable, 16);//16         
  } 
  } 
getCircleBitmap 방법 과 하위 스 레 드 코드:

private Bitmap bitmap; 
  private boolean isCreateBitmap = false; 
  private Canvas canvas; 
  private PorterDuffXfermode pdf; 
  private Paint bitmapPaint; 
 
  private Bitmap getCircleBitmap(Bitmap image, int width, float rotate) { 
    if (!isCreateBitmap) {//                  
      bitmapPaint = new Paint(); 
      bitmapPaint.setAntiAlias(true);//    
      bitmapPaint.setDither(true);//    ....       
      bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);//           bitmap 
      isCreateBitmap = true; 
      canvas = new Canvas(bitmap);//     bitmap       
      canvas.drawCircle(width / 2, width / 2, width / 2, bitmapPaint);//        
      pdf = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);//                   
    } 
    bitmapPaint.setXfermode(pdf);//       
if (rotate_fx==0) { 
    canvas.rotate(rotate, width / 2, width / 2);//    
   } else {//    :                      
 
    canvas.rotate(-rotate, width / 2, width / 2);//    
   } 
    canvas.drawBitmap(image, 0, 0, bitmapPaint);//    ,(      ) 
    bitmapPaint.setXfermode(null); 
    return bitmap;//  bitmap       ,  ,          bitmap 
  } 
 
  private Handler handler = new Handler(); 
  private Runnable runnable = new Runnable() { 
    @Override 
    public void run() { 
      invalidate();//     
    } 
  }; 
처음 onDraw 방법 을 실 행 했 을 때 0.8 도 회전 한 bitmap 를 얻 었 습 니 다.그리고 16 밀리초 후에 하위 스 레 드 리 셋 을 시작 하고 onDraw 를 다시 실행 하여 0.8 도 회전 하 는 bitmap 를 얻 었 습 니 다.이런 식 으로 계속 회전 합 니 다.빨리 돌 고 싶 으 면 매번 회전 하 는 각 도 를 좀 높 여 라.그러나 너무 크게 돌 면 안 된다.그렇지 않 으 면 효과 가 매우 좋 지 않다.찰싹 찰싹.이렇게 해서 이 사용자 정의 view 를 완 성 했 습 니 다.매우 간단 하지만 저 는 오랫동안 괴 롭 혔 습 니 다.주로 측정 할 때 세심 하지 못 했 습 니 다.실현 방법 은 모두 스스로 만 든 것 이 니 더 좋 은 실현 방법 이 있다 면 알려 주 십시오.
마지막 으로 두 가지 방법 을 외부 에 노출 시 키 겠 습 니 다.

public void startRotate() {//     
    if (!isRotate) { 
      this.isRotate = true; 
      invalidate(); 
    } 
  } 
 
  public void stopRotate() {//     
    isRotate = false; 
  } 
그리고 레이아웃 에서 해 볼 수 있 습 니 다.

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:app="http://schemas.android.com/apk/res-auto" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:fitsSystemWindows="true" 
  android:orientation="vertical"> 
 
<com.as.liji.jishiben.view.RotateCircleImageView 
    android:id="@+id/rcv" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_centerInParent="true" 
    app:circle_back_width="80dp" 
    app:image="@mipmap/sm" 
    app:isRotate="false" 
    app:rotate_fx="0" 
    app:rotate_sd="0.5" /> 
 
  <TextView 
    android:id="@+id/tv" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_below="@id/rcv" 
    android:layout_centerHorizontal="true" 
    android:ellipsize="marquee" 
    android:text="    :     --Hold On" /> 
 
  <LinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_below="@id/tv" 
    android:orientation="horizontal"> 
 
    <Button 
      android:layout_width="0dp" 
      android:layout_height="wrap_content" 
      android:layout_weight="1" 
      android:onClick="startRotate" 
      android:text="  " /> 
 
    <Button 
      android:layout_width="0dp" 
      android:layout_height="wrap_content" 
      android:layout_weight="1" 
      android:onClick="stopRotate" 
      android:text="  " /> 
  </LinearLayout> 
 
</RelativeLayout> 
activity 에서 컨트롤 을 받 고 두 단 추 를 다시 쓰 는 클릭 이벤트 방법:

private RotateCircleImageView rcv; 
 
........onCreate(){ 
........ 
rcv = (RotateCircleImageView) findViewById(R.id.rcv); 
} 
public void startRotate(View v) { 
    rcv.startRotate(); 
  } 
 
  public void stopRotate(View v) { 
    rcv.stopRotate(); 
  } 

이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기