最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android自定義View實(shí)現(xiàn)旋轉(zhuǎn)的圓形圖片

 更新時(shí)間:2021年06月24日 12:07:55   作者:Moing557  
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)旋轉(zhuǎn)的圓形圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

自定義View是android開發(fā)的一個(gè)重要技能,用android提供的2/3D繪制相關(guān)類可以實(shí)現(xiàn)非常多炫酷的效果,需要實(shí)打?qū)嵉木幊袒A(chǔ)。

但是自定義View又是我的弱項(xiàng),所以最近都在摸索、練習(xí)自定義View。今天我寫了一個(gè)圓形圖片,同時(shí)不斷勻速旋轉(zhuǎn)的RotateCircleImageView。實(shí)現(xiàn)方法是自己想的,但肯定不是最好的實(shí)現(xiàn)方法。

自定義View分四步。

一:自定義屬性;
二:創(chuàng)建自定義View,在構(gòu)造方法中拿到自定義屬性;
三:重寫onMeasure方法;
四:重寫onDraw方法

先來個(gè)效果圖

先在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> 

創(chuàng)建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的三個(gè)構(gòu)造函數(shù),用一參的調(diào)用二參的,用二參的調(diào)用三參的。在三參的構(gòu)造里初始化參數(shù)。

private Bitmap image; 
private Bitmap tempImage; 
private Paint paint; 
private int bkWidth;//黑色圓邊框的寬度 
private int rotate_fx=0;//旋轉(zhuǎn)方向 0=順時(shí)針 1=逆時(shí)針 
private float rotateSD = 0.8f;//每次旋轉(zhuǎn)的角度--建議范圍0.1f-1,否則會(huì)抖動(dòng) 
private boolean isRotate = false;//控制是否旋轉(zhuǎn) 
 private void initData() { 
    paint = new Paint(); 
    paint.setAntiAlias(true); 
    paint.setDither(true); 
    TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, 
        R.styleable.RotateCircleImageView, defStyleAttr, 0);//用這個(gè)類獲得自定義的屬性 

    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是我的一個(gè)工具類,將dp轉(zhuǎn)換成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); 
} 

重寫測量方法:主要是測量包裹內(nèi)容的情況下寬度和高度的值

@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;//預(yù)測寬度,先假設(shè)它等于指定大小或填充窗體 
    if (widthMode == MeasureSpec.EXACTLY) { 
      mWidth = widthSize;//如果是指定大小或填充窗體(以后直接說成指定大?。?直接設(shè)置最終寬度 
 
    } else { 
      yy_width=tempImage.getWidth();//如果是包裹內(nèi)容,則預(yù)測寬度等于圖片寬度 
      mWidth = yy_width + getPaddingLeft() + getPaddingRight();//最終寬度等于預(yù)測寬度加 左右Padding寬度 
    } 
    if (heightMode == MeasureSpec.EXACTLY) { 
      mHeight = heightSize;//同上 
    } else { 
      mHeight = getPaddingTop() + getPaddingBottom() + yy_width;//最終高度等于預(yù)測寬度加 上下Padding寬度 
                   //目的是讓控件的寬高相等,但Padding是可以由用戶自由指定的,所以再加上padding 
 } 
    if (tempImage.getHeight() < tempImage.getWidth()) { 
    //這里用Bitmap類提供的縮放方法把圖片縮放成指定大小,如果圖片高度比寬度小,則強(qiáng)制拉伸 
      image = Bitmap.createScaledBitmap(tempImage, yy_width - bkWidth, 
          yy_width - bkWidth, false); 
    } else { 
      
    //這里用Bitmap類提供的縮放方法把圖片縮放成指定大?。▽挾鹊扔陬A(yù)測的寬度,高度按比例縮放) 
    //該方法根據(jù)參數(shù)的寬高強(qiáng)制縮放圖片,所以這里根據(jù)寬度算出縮放后的高度 
      image = Bitmap.createScaledBitmap(tempImage, yy_width - bkWidth,(int) (tempImage.getHeight() / 
      (((float) tempImage.getWidth()) / yy_width) - bkWidth), false); 
    } 
  setMeasuredDimension(mWidth, mHeight);//設(shè)置View的寬高,測量結(jié)束 
  } 

假如寬度是指定大小,我希望高度根據(jù)這個(gè)大小按比例縮放,那么我需要拿到圖片原始大小,所以需要一個(gè)tempImage,為什么寫一個(gè)臨時(shí)的Bitmap?因?yàn)槲覝y試的時(shí)候發(fā)現(xiàn)   假如我用這個(gè)image直接把Bitmap.createScaledBitmap(image,xx,xx,false);的返回值賦給image的話,即使我在這行代碼前去用image.getWidth()和Image.getHeight(),返回的值都已經(jīng)變成縮放后的大小,而不是原始大小,這讓我感到很奇怪。難道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毫秒后啟動(dòng)子線程 
  } 
  } 

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) {//節(jié)約資源所以這些代碼只需要執(zhí)行一次 
      bitmapPaint = new Paint(); 
      bitmapPaint.setAntiAlias(true);//抗鋸齒 
      bitmapPaint.setDither(true);//忘了是啥....反正效果好點(diǎn) 
      bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);//創(chuàng)建一個(gè)指定寬高的空白bitmap 
      isCreateBitmap = true; 
      canvas = new Canvas(bitmap);//用那個(gè)空白bitmap創(chuàng)建一個(gè)畫布 
      canvas.drawCircle(width / 2, width / 2, width / 2, bitmapPaint);//在畫布上畫個(gè)圓 
      pdf = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);//創(chuàng)建一個(gè)混合模式為保留后者相交的部分 
    } 
    bitmapPaint.setXfermode(pdf);//設(shè)置混合模式 
if (rotate_fx==0) { 
    canvas.rotate(rotate, width / 2, width / 2);//順時(shí)針 
   } else {//旋轉(zhuǎn)畫布:意思是下一次繪制的內(nèi)容會(huì)被旋轉(zhuǎn)這么多個(gè)角度 
 
    canvas.rotate(-rotate, width / 2, width / 2);//逆時(shí)針 
   } 
    canvas.drawBitmap(image, 0, 0, bitmapPaint);//繪制圖片,(圖片會(huì)被旋轉(zhuǎn)) 
    bitmapPaint.setXfermode(null); 
    return bitmap;//這個(gè)bitmap在畫布中被旋轉(zhuǎn),畫圓,返回后就是一個(gè)圓形的bitmap 
  } 
 
  private Handler handler = new Handler(); 
  private Runnable runnable = new Runnable() { 
    @Override 
    public void run() { 
      invalidate();//刷新界面 
    } 
  }; 

在第一次執(zhí)行onDraw方法的時(shí)候得到的是一個(gè)旋轉(zhuǎn)了0.8度的bitmap,然后16毫秒后啟動(dòng)子線程刷新,再次執(zhí)行onDraw,得到一個(gè)再次旋轉(zhuǎn)0.8度的bitmap,以此類推,所以不斷旋轉(zhuǎn)。想要轉(zhuǎn)的快一點(diǎn)就把每次旋轉(zhuǎn)的角度調(diào)大一點(diǎn),但是不能太大,否則效果很不好。一卡一卡的。這樣就完成了這個(gè)自定義view,非常簡單,但是我卻折騰了好久,主要還是測量的時(shí)候不夠細(xì)心。實(shí)現(xiàn)方法都是自己整出來的,如果有更好的實(shí)現(xiàn)方法歡迎告知。

最后再暴露兩個(gè)方法給外部

public void startRotate() {//開始旋轉(zhuǎn) 
    if (!isRotate) { 
      this.isRotate = true; 
      invalidate(); 
    } 
  } 
 
  public void stopRotate() {//暫停旋轉(zhuǎn) 
    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中拿到控件,重寫兩個(gè)按鈕的點(diǎn)擊事件方法:

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

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 用Android實(shí)現(xiàn)京東秒殺功能詳解

    用Android實(shí)現(xiàn)京東秒殺功能詳解

    大家好,本篇文章主要講的是用Android實(shí)現(xiàn)京東秒殺功能詳解,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-01-01
  • Android串口開發(fā)之使用JNI實(shí)現(xiàn)ANDROID和串口通信詳解

    Android串口開發(fā)之使用JNI實(shí)現(xiàn)ANDROID和串口通信詳解

    這篇文章主要給大家介紹了關(guān)于Android串口開發(fā)之使用JNI實(shí)現(xiàn)ANDROID和串口通信的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • Android binder 匿名服務(wù)實(shí)現(xiàn)雙向通信的解決方案

    Android binder 匿名服務(wù)實(shí)現(xiàn)雙向通信的解決方案

    這篇文章主要介紹了Android binder 匿名服務(wù)實(shí)現(xiàn)雙向通信的解決方案,當(dāng)然,這種方案是可行的,只是需要client和server都向servicemanager注冊(cè)一個(gè)服務(wù),實(shí)現(xiàn)起來有點(diǎn)麻煩,不太建議這么做,需要的朋友可以參考下
    2024-04-04
  • Android中的OpenGL使用配置詳解

    Android中的OpenGL使用配置詳解

    這篇文章主要為大家介紹了Android中的OpenGL使用配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Android中Home鍵的監(jiān)聽和攔截示例

    Android中Home鍵的監(jiān)聽和攔截示例

    本篇文章主要介紹了Android中Home鍵的監(jiān)聽和攔截示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • android控件之WebView控件縮小

    android控件之WebView控件縮小

    發(fā)現(xiàn)這個(gè)控件挺好用,能自已控制進(jìn)度條,而且這個(gè)控件的功能非常壯大,先上個(gè)簡單的
    2013-05-05
  • Android封裝MVP實(shí)現(xiàn)登錄注冊(cè)功能

    Android封裝MVP實(shí)現(xiàn)登錄注冊(cè)功能

    這篇文章主要為大家詳細(xì)介紹了Android封裝MVP實(shí)現(xiàn)登錄注冊(cè)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Android7.0實(shí)現(xiàn)拍照和相冊(cè)選取圖片功能

    Android7.0實(shí)現(xiàn)拍照和相冊(cè)選取圖片功能

    這篇文章主要為大家詳細(xì)介紹了Android7.0實(shí)現(xiàn)拍照和相冊(cè)選取圖片功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Android基于Toolbar實(shí)現(xiàn)頂部標(biāo)題欄及后退鍵

    Android基于Toolbar實(shí)現(xiàn)頂部標(biāo)題欄及后退鍵

    這篇文章主要介紹了Android基于Toolbar實(shí)現(xiàn)頂部標(biāo)題欄及后退鍵,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Android自定義控件之自定義屬性(二)

    Android自定義控件之自定義屬性(二)

    這篇文章主要為大家詳細(xì)介紹了Android自定義控件之自定義屬性,如何給自定義控件自定義一些屬性,感興趣的小伙伴們可以參考一下
    2016-08-08

最新評(píng)論

阜南县| 嵩明县| 什邡市| 临邑县| 高阳县| 旬阳县| 色达县| 洛宁县| 通化市| 望都县| 云南省| 垫江县| 甘孜县| 白银市| 齐齐哈尔市| 包头市| 桃园县| 吉隆县| 大余县| 屏南县| 耿马| 桦甸市| 绥芬河市| 莆田市| 昆山市| 双桥区| 木兰县| 潞城市| 新竹市| 宜君县| 江安县| 原阳县| 枣阳市| 沂水县| 霞浦县| 青龙| 石嘴山市| 定州市| 南部县| 扬中市| 苍山县|