1. 程式人生 > >android自定義view-打造圓形ImageView(一)

android自定義view-打造圓形ImageView(一)

package com.beyole.view;

import com.beyole.roundimageview.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Bitmap.Config;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;

public class RoundImageView extends ImageView {
	// ImageView型別
	private int type;
	// 圓形圖片
	private static final int TYPE_CIRCLE = 0;
	// 圓角圖片
	private static final int TYPE_ROUND = 1;
	// 預設圓角寬度
	private static final int BORDER_RADIUS_DEFAULT = 10;
	// 獲取圓角寬度
	private int mBorderRadius;
	// 畫筆
	private Paint mPaint;
	// 半徑
	private int mRadius;
	// 縮放矩陣
	private Matrix mMatrix;
	// 渲染器,使用圖片填充形狀
	private BitmapShader mBitmapShader;
	// 寬度
	private int mWidth;
	// 圓角範圍
	private RectF mRectF;

	public RoundImageView(Context context) {
		this(context, null);
	}

	public RoundImageView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// 初始化畫筆等屬性
		mMatrix = new Matrix();
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		// 獲取自定義屬性值
		TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundImageView, defStyle, 0);
		int count = array.getIndexCount();
		for (int i = 0; i < count; i++) {
			int attr = array.getIndex(i);
			switch (attr) {
			case R.styleable.RoundImageView_borderRadius:
				// 獲取圓角大小
				mBorderRadius = array.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, BORDER_RADIUS_DEFAULT, getResources().getDisplayMetrics()));
				break;
			case R.styleable.RoundImageView_imageType:
				// 獲取ImageView的型別
				type = array.getInt(R.styleable.RoundImageView_imageType, TYPE_CIRCLE);
				break;
			}
		}
		// Give back a previously retrieved StyledAttributes, for later re-use.
		array.recycle();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		// 如果是圓形,則強制寬高一致,以最小的值為準
		if (type == TYPE_CIRCLE) {
			mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
			mRadius = mWidth / 2;
			setMeasuredDimension(mWidth, mWidth);
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (getDrawable() == null) {
			return;
		}
		// 設定渲染器
		setShader();
		if (type == TYPE_ROUND) {
			canvas.drawRoundRect(mRectF, mBorderRadius, mBorderRadius, mPaint);
		} else {
			canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
		}
	}

	private void setShader() {
		Drawable drawable = getDrawable();
		if (drawable == null) {
			return;
		}
		Bitmap bitmap = drawable2Bitmap(drawable);
		mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
		float scale = 1.0f;
		if (type == TYPE_ROUND) {
			scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight() * 1.0f / bitmap.getHeight());
		} else if (type == TYPE_CIRCLE) {
			// 取小值,如果取大值的話,則不能覆蓋view
			int bitmapWidth = Math.min(bitmap.getWidth(), getHeight());
			scale = mWidth * 1.0f / bitmapWidth;
		}
		mMatrix.setScale(scale, scale);
		mBitmapShader.setLocalMatrix(mMatrix);
		mPaint.setShader(mBitmapShader);
	}

	/**
	 * 將Drawable轉化為Bitmap
	 * 
	 * @param drawable
	 * @return
	 */
	private Bitmap drawable2Bitmap(Drawable drawable) {
		if (drawable instanceof BitmapDrawable) {
			BitmapDrawable bd = (BitmapDrawable) drawable;
			return bd.getBitmap();
		}
		int w = drawable.getIntrinsicWidth();
		int h = drawable.getIntrinsicHeight();
		// 建立畫布
		Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		drawable.setBounds(0, 0, w, h);
		drawable.draw(canvas);
		return bitmap;
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		mRectF = new RectF(0, 0, getWidth(), getHeight());
	}

	/**
	 * 對外公佈的設定borderRadius方法
	 * 
	 * @param borderRadius
	 */
	public void setBorderRadius(int borderRadius) {
		int pxValue = dp2px(borderRadius);
		if (this.mBorderRadius != pxValue) {
			this.mBorderRadius = pxValue;
			// 這時候不需要父佈局的onLayout,所以只需要呼叫onDraw即可
			invalidate();
		}
	}

	/**
	 * 對外公佈的設定形狀的方法
	 * 
	 * @param type
	 */
	public void setType(int type) {
		if (this.type != type) {
			this.type = type;
			if (this.type != TYPE_CIRCLE && this.type != TYPE_ROUND) {
				this.type = TYPE_CIRCLE;
			}
			// 這個時候改變形狀了,就需要呼叫父佈局的onLayout,那麼此view的onMeasure方法也會被呼叫
			requestLayout();
		}
	}

	/**
	 * dp2px
	 */
	public int dp2px(int val) {
		return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, val, getResources().getDisplayMetrics());
	}
}
我這裡還公佈了兩個方法,一個是設定type,一個是設定圓角圖片的borderRadius。你會發現這兩種方法重繪view的時候使用了兩種不同的方法,一個是invalidate(),一個是requestLayout()。這兩個方法的區別就是,invalidate相當於呼叫View.onDraw()方法,而requestLayout()是當view確定自身已經不再適合現有的區域時,呼叫該方法要求parent view重新呼叫它的onMeasure和onLayout來重新設定自己。

相關推薦

android定義view-打造圓形ImageView()

package com.beyole.view; import com.beyole.roundimageview.R; import android.content.Context; import android.content.res.TypedArray; import android.graphi

android定義view-打造圓形ImageView(四)終結篇

package com.beyole.view; import java.lang.ref.WeakReference; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitm

android定義view-打造圓形ImageView(二)

package com.beyole.view; import java.lang.ref.WeakReference; import android.content.Context; import android.content.res.TypedArray; import android.graphi

Android 定義View實現圓形環繞效果

之前專案中需要實現一個四周環繞中心圓形頭像的效果,感覺還是自定義比較方便,於是就自己封裝了一個控制元件去實現。先貼張圖顯示最終效果。 首先自定義一個View繼承自LinearLayout,通過動態新增childView的方式將子控制元件新增到View中。思路是先新增中間圓形頭像

Android定義view-繪製圓形進度條

詳細可參考:http://blog.csdn.net/Beyond0525/article/details/48181345最近專案上有一些需求,需要繪製圓形的進度條滿足設計上和互動上的需求: 實現思路在畫布上直接繪製View,需要了解一下幾點 1.需要畫一個圓 2.圓圈上有

Android 定義View實現圓形切圖的效果

使用自定義View實現圓形ImageView的效果 目前圓形邊框還需要調整,這裡有點問題 實現思路 使用一個Paint,將得到的Bitmap設定成paint的Shader,設定完成後,使用Matrix調整圖片至居中,使用RectF約束邊框,最後完成

Android定義view-打造酷炫的字型滑動高亮控制元件

前言: 相信很多時候開發會遇到類似於音樂歌詞同步,播放到哪句歌詞的哪個詞時會逐漸高亮,這樣的描述還是不夠準確,iPhone的滑動解鎖的那種效果,相信很多人都會熟悉吧。今天,我們的首要任務就是開發一個類似於這種效果的安卓控制元件,以便在以後的專案中直接使用,看起來高大上有木有

Android 定義View--ProgressBar篇(

1、概述 1.1 目的 : 在我們的日常開發中,有很多Android UI介面上有一些特殊或者特別的控制元件與介面,是Android自帶的控制元件所不能滿足的,需要我們自己定製一些適合的控制元件來完成。 1.2 Android自定義View步驟 : 自定

Android定義View圓形頭像

記錄貼 現在製作圓形頭像的第三方工具已經很多了,本帖只為記錄自定義view學習過程。 1.主體程式碼部分 public class CirclePhotoView extends View { private int max;//最大進度 private

android定義view之地圖(

最近參加了一個比賽,要用到自己做一個自定義的小地圖,所以在網上查找了一些關於自定義view的有關資料,也瞭解了自定義控制元件的初步知識。 效果圖 第一階段我畫了一個自制的網格圖,點哪個網格就會哪個網格就會顯示。 工作環境圖 程式碼介紹

Android定義view之屬性動畫

Android 裡動畫是有一些分類的:動畫可以分為兩類:Animation 和 Transition;其中 Animation 又可以再分為 View Animation 和 Property Animation 兩類: View Animation 是純粹基於 framew

Android 定義View實現圓形進度條 深入理解onDraw和onMeasure及定義屬性

Android的View類是使用者介面的基礎構件,表示螢幕上的一塊矩形區域,負責這個區域的繪製和事件處理。自定義View的過程主要包括重寫onDraw及onMeasure方法 , 其中onMeasure方法的作用就是計算出自定義View的寬度和高度。這個計算的過

android 定義View載入圓形進度條

實現效果如下: 主要步驟如下幾步: 1.記載自定義屬性的值: public CircleProgressBar(Context context, @Nullable AttributeS

android定義View打造自己的專屬控制元件——風車控制元件

Android 自定義View——打造自己的專屬控制元件 前段時間看到一個天氣應用,介面做的很好看。裡面一個風車轉動動畫和一個日出日落的動畫挺有意思的,於是自己也照著他的介面做了一個。 先看一下介面 自定義View一般有兩種情況 繼承自原有控制元件

Android定義view),打造絢麗的驗證碼

前言:我相信信念的力量,信念可以支撐起一個人,一個名族,一個國家。正如“人沒有夢想和鹹魚有什麼區別”一樣,我有信念,有理想,所以我正在努力向著夢想前進~。 自定義view,如果是我,我首先要看到自定義view的效果圖,然後再想想怎麼實現這種效果或功能,所以先貼

Android定義View--翻書控制元件(

0.前言 最近重看了一遍封神演義,感覺QQ閱讀那個翻書的效果挺好的,準備做一個。上週五下午用了兩個小時只寫了一部分功能,以後有時間再完善 1.分析 先看效果圖 這個空間,說簡單也簡單,說難也難,簡單就在於這個效果主要就是依賴canvas的clippath才見到部分canvas,難就難在裁

Android 定義View

前言:可是有時候我們總感覺官方定義的一些基本元件不夠用,自定義元件就不可避免了。那麼如何才能做到像官方提供的那些元件一樣用xml來定義他的屬性呢? 先總結下自定義View的步驟: 1、自定義View的屬性; 2、在View的構造方法中獲得自定義的屬性。 一、在re

Android定義View的實現方法,帶你步步深入瞭解View(四)

不知不覺中,帶你一步步深入瞭解View系列的文章已經寫到第四篇了,回顧一下,我們一共學習了LayoutInflater的原理分析、檢視的繪製流程、檢視的狀態及重繪等知識,算是把View中很多重要的知識點都涉及到了。如果你還沒有看過我前面的幾篇文章,建議先去閱讀一下,多瞭解一些

Android定義View的實現方法 帶你步步深入瞭解View

                不知不覺中,帶你一步步深入瞭解View系列的文章已經寫到第四篇了,回顧一下,我們一共學習了LayoutInflater的原理分析、檢視的繪製流程、檢視的狀態及重繪等知識,算是把View中很多重要的知識點都涉及到了。如果你還沒有看過我前面的幾篇文章,建議先去閱讀一下,多瞭解一些原

android定義View)、正弦波水波紋

文章目錄 1、正弦曲線知識 2、靜態正弦曲線繪製 3、動態正弦曲線繪製 4、完整原始碼 1、正弦曲線知識 對這個初中知識遺忘了的可以先看看正弦曲線百度百科詞條方便加深理解。