Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android開發萬能圓角ImageView

android開發萬能圓角ImageView

編輯:關於Android編程

網上demo的效果:
這裡寫圖片描述
差不多應該是這樣的,但是容易出一些問題,比如你的圖片本身就是個圓角?又或者圖片太大,你想縮小顯示,但出現顯示內容不全?
我想實現的效果是這樣的:
這裡寫圖片描述vcejrLWxyLuzpLe90M7Ssr/J0tS1xKOs0vLOqs7SytTBy9CnufujrMO709DOyszio6zE48PHtb3Ksbryv8nS1NfUvLqzosrUoaM8YnIgLz4NCrLOv7zOxNXCo7o8YSBocmVmPQ=="http://blog.csdn.net/lmj623565791/article/details/41967509">http://blog.csdn.net/lmj623565791/article/details/41967509
這是翔神的文章,不過他的效果,並不是我想要的,因為,他的繪圖是從(0,0)點然後截取寬高繪圖,並不是我想要的重中間截取,然後繪圖。
大體代碼和他的差不多。不過依舊刪除了一些無用的代碼(哈哈,這個我抄代碼的特性,沒用放著干嘛,礙眼。)
好了下面上代碼:
初始化:

  private void inital(Context context, AttributeSet attrs) {
        matrix = new Matrix();
        paint = new Paint();
        //無鋸齒
        paint.setAntiAlias(true);
        TypedArray array = context.obtainStyledAttributes(attrs,
                R.styleable.RoundAngelImageView);

        //如果沒設置圓角的默認值,在這設置默認值為10dp
        BorderRadius=dp2px(BODER_RADIUS_DEFAULT);
        // 默認為Circle
        type = array.getInt(R.styleable.RoundAngelImageView_type, TYPE_CIRCLE);
        array.recycle();
    }

這邊我用到了dp2px。這個就是將dp轉換成px。網上代碼一堆~~~~:

 public int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dp, getResources().getDisplayMetrics());
    }

既然繼承了ImageView,少不了的自然是onmeusre方法:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //如果類型是圓形,則強制改變view的寬高一致,以小值為准
        if (type == TYPE_CIRCLE) {
            width = Math.min(getMeasuredWidth(), getMeasuredHeight());
            radius = width / 2;
            setMeasuredDimension(width, width);
        }
    }

下面就是重點了,對bitmapshader不了解的,去看看這個:http://blog.csdn.net/aigestudio/article/details/41799811

設置bitmapshader的代碼如下:

  Drawable drawable = getDrawable();
        if (drawable == null) {
            return;
        }
        //將drawable轉化成bitmap對象
          Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
        if (bitmap == null) {
            return;
        }
        // 將bmp作為著色器,就是在指定區域內繪制bmp
        BitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        float scale = 1.0f;
        int viewwidth = getWidth();
        int viewheight = getHeight();
        int drawablewidth = bitmap.getWidth();
        int drawableheight = bitmap.getHeight();
        float dx = 0, dy = 0;
        if (type == TYPE_CIRCLE) {
            // 拿到bitmap寬或高的小值
            int size = Math.min(bitmap.getWidth(), bitmap.getHeight());
            scale = width * 1.0f / size;

        } else if (type == TYPE_ROUND) {
            // 如果圖片的寬或者高與view的寬高不匹配,計算出需要縮放的比例
            // 縮放後的圖片的寬高,一定要大於我們view的寬高;所以我們這裡取大值
            scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight()
                    * 1.0f / bitmap.getHeight());
        }

        if (drawablewidth * viewheight > viewwidth * drawableheight) {
            dx = (viewwidth - drawablewidth * scale) * 0.5f;
        } else {
            dy = (viewheight - drawableheight * scale) * 0.5f;
        }

        // shader的變換矩陣,我們這裡主要用於放大或者縮小
        matrix.setScale(scale, scale);
        matrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
        // 設置變換矩陣
        BitmapShader.setLocalMatrix(matrix);
        // 設置shader
        paint.setShader(BitmapShader);

如果有人看了前面我給的參考文章,那麼,你可以發現,我把這個類的代碼進行了改動,差不多就是把圖片的起點坐標從(0,0)移動到了我想要的起點。
至於為什麼,我們打開ImageView的源碼,找到Center_Crop。這快代碼的意思差不多是將圖片居中把。
來,我們上源碼:

if (ScaleType.CENTER_CROP == mScaleType) {
                mDrawMatrix = mMatrix;

                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight; 
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));

他怎麼計算的scale我們別管它,重點是如何計算他的dx和dy。
這裡我就舉個例子來計算。drawable的寬和高是(300,200)。我要繪制的view的寬高是(200,200)。按照 我的思路繪圖是從(50,0)到(250,250),而不是(0,0)到(200,200)。
話不多說。我們看源碼的計算:

dw*vh=300*200;
dh*vw=200*200;
/*
此時我們需要得到dx的值,dy默認為0,我的起點是(50,0),似乎是對的?我們接著計算
*/
  scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight()* 1.0f / bitmap.getHeight());
/**
那麼我們的scale=math.max(200/300,200/200)=1
*/

  dx = (vwidth - dwidth * scale) * 0.5f;
  /**
  那麼dx=(200-300*1)*05=-50,和我想要的50越來越近的,那麼為什麼他postTranslate的時候是(-50,0)而不是(50,0)?
  */

我們畫圖,來說明這一切,看完圖,你或許就懂了。
這裡寫圖片描述
紅色框是我們之後的,那這樣,1這塊區域可以理解成沒了。銷毀了。但是實際的效果是這樣:
這裡寫圖片描述
圓形好像看似沒什麼問題,那你們自己看圓角圖片左邊是不是被拉伸,這個拉伸距離應該剛好是我們之前計算得到的50dp。因為上圖的1那塊已經不存在了,所以你畫圖的時候那快距離就是拉伸的距離。現在我們看看-50dp的圖。
這裡寫圖片描述
1的部分被移出去了。但他依然是存在的,所以繪制的圖是不會出現任何拉伸的。perfect~~~。
屬性配置完了,剩下的就是ondraw方法咯。很簡單,代碼如下:

protected void onDraw(Canvas canvas) {
        if (getDrawable() == null) {
            return;
        }
        setBitmapShader();
        if (type == TYPE_ROUND) {
            canvas.drawRoundRect(rectF, BorderRadius, BorderRadius,
                    paint);
        } else {
            canvas.drawCircle(radius, radius, radius, paint);
        }
    }

當然你也得考慮到onsizechanged的時候,代碼也不多:

 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 圓角圖片的范圍
        if (type == TYPE_ROUND)
            rectF = new RectF(0, 0, getWidth(), getHeight());
    }

好了。在這邊我補上attrs屬性:

 
    
        
        
    


    
        
        
    

現在。一個完美的,萬能的圓角ImageVIew就解決了。不過好像還缺點什麼,對了。自行修改圓角,自行修改類型,加上這個才算完美。
附上代碼:

  //修改圓角大小
    public void setBorderRadius(int borderRadius) {
        int px = dp2px(borderRadius);
        if (this.BorderRadius != px) {
            this.BorderRadius = px;
            invalidate();
        }
    }

    //修改type
    public void setType(int type) {
        if (this.type != type) {
            this.type = type;
            if (this.type != TYPE_ROUND && this.type != TYPE_CIRCLE) {
                this.type = TYPE_CIRCLE;
            }
            requestLayout();
        }

    }

現在我們新建個xml。放2張圖片。一個圓角,一個圓形,先看看效果如何:

  

        

        
    

多張圖片在外層加一個scrollview。好了。我們來看一下效果:
這裡寫圖片描述
完美~~
圓角大小自行修改。類型自行修改。好了。今天主要內容就這麼多把。
整理了2個多小時~也是夠夠的。
感覺還有一些常用的控件,帶刪除鍵的edittext。以及可見不可見的edittext。似乎不難。(有空在研究)。
最後,問你們個問題,忙活了一天沒解決。你們用android.suport.design包是怎麼用的。為什麼我rebuild之後是這樣。
這裡寫圖片描述
這是什麼鬼。不懂。
好了,今天就說到這邊把,能解決我問題的請留言,謝謝。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved