編輯:關於Android編程
在Android的實際開發中,我們Android系統本身已經給我們提供了很豐富的UI以及各種實用的控件,例如TextView,Button,ImageView等。用這些基礎控件已經能夠實現非常優美的界面以及功能。然而在實際的開發中,我們由於客戶的各種需求,App開發的各種標新立異,追求個性化,所以,導致我們用這些最基礎的控件已經不能夠滿足我們的各種個性化需求。那麼,我們就要考慮去自定義控件來完成我們的要求,要真正去完成一個自定義控件,我們先來看看這個控件的繼承體系:
Android 應用中的所有用戶界面元素都是使用 View 和 ViewGroup 對象構建而成。View 對象用於在屏幕上繪制可供用戶交互的內容。ViewGroup 對象用於儲存其他 View(和 ViewGroup)對象,以便定義界面的局部。
Android 提供了一系列 View 和 ViewGroup 子類,可為您提供常用輸入控件(如按鈕和文本字段)和各種布局模式(如線性布局或相對布局)。
綜上所述:View的關鍵生命周期為:
構造View() –> onMeasure() –> onSizeChanged() –> onLayout() –> onDraw()
構造函數
public CustomView(Context context) { super(context); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }首先在res的values文件夾下面建一個attrs.xml文件,如下圖所示:
首先應該在布局文件的跟布局當中定義命名空間
xmlns:app="http://schemas.android.com/apk/res-auto"在xml中的用法:如下所示
app:border_width="2dp" />
最後在構造函數中這樣獲取:
public CircleImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); super.setScaleType(SCALE_TYPE); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); int mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH); int mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR); a.recycle(); }
在xml中可以定義的屬性如下
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); System.out.println(widthMeasureSpec+":"+heightMeasureSpec); // 如果是自定ViewGroup,計算自定義的ViewGroup中所有子控件的大小 //measureChildren(widthMeasureSpec, heightMeasureSpec); int w = getMeasureWidth(widthMeasureSpec); int h = getMeasureHeight(heightMeasureSpec); setMeasuredDimension(w, h); \\必須調用此方法,否則會拋出異常 } private int getMeasureHeight(int heightMeasureSpec) { int result = 0; int size = MeasureSpec.getSize(heightMeasureSpec); \\每次調用此方法,測量用到的size會發生變化 int mode = MeasureSpec.getMode(heightMeasureSpec); \\根據定義的Layout_width,Layout_height,會對此值產生影響 if (mode == MeasureSpec.EXACTLY) { result = size; } else if (mode == MeasureSpec.UNSPECIFIED) { result = (int) paint.measureText("") + getPaddingLeft() + getPaddingRight(); } else { result = Math.min(result, size); } System.out.println("Height size:" + size); System.out.println("Height mode:" + mode); return result; } private int getMeasureWidth(int widthMeasureSpec) { int result = 0; int size = MeasureSpec.getSize(widthMeasureSpec); int mode = MeasureSpec.getMode(widthMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else if (mode == MeasureSpec.UNSPECIFIED) { result = (int) paint.measureText("") + getPaddingTop() + getPaddingBottom(); } else { result = Math.min(result, size); } System.out.println("Width size:" + size); System.out.println("Width mode:" + mode); return result; }MeasureSpec
從上面可以看出 onMeasure 函數中有 widthMeasureSpec 和 heightMeasureSpec 這兩個 int 類型的參數, 毫無疑問他們是和寬高相關的, 但它們其實不是寬和高, 而是由寬、高和各自方向上對應的測量模式來合成的一個值:對於詳細測量值( measureSpec )需要兩樣東西來確定它,那就是大小(size)和模式(mode)。 而 measureSpec,size,mode他們三個的關系,都封裝在View類中的一個內部類裡,名叫 MeasureSpec 。
測量模式一共有三種, 被定義在 Android 中的 View 類的一個內部類View.MeasureSpec中:
我們重寫onMeasure()所要實現的最終目的。它的作用就是存儲我們測量好的寬高值。
因為View的大小不僅由View本身控制,而且受父控件的影響,所以我們在確定View大小的時候最好使用系統提供的onSizeChanged回調函數。它又四個參數,分別為 寬度,高度,上一次寬度,上一次高度。這個函數比較簡單,我們只需關注 寬度(w), 高度(h) 即可,這兩個參數就是View最終的大小。
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); }
確定布局的函數是onLayout,它用於確定子View的位置,在自定義ViewGroup中會用到,他調用的是子View的layout函數。在自定義ViewGroup中,onLayout一般是循環取出子View,然後經過計算得出各個子View位置的坐標值,然後用以下函數設置子View位置。
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 記錄總高度 int mTotalHeight = 0; // 遍歷所有子視圖 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); // 獲取在onMeasure中計算的視圖尺寸 int measureHeight = childView.getMeasuredHeight(); int measuredWidth = childView.getMeasuredWidth(); childView.layout(l, mTotalHeight, measuredWidth, mTotalHeight + measureHeight); mTotalHeight += measureHeight; } }四個參數分別為:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //利用Canvas 畫圖 }
Canvas(畫布)類
畫筆屬性設置好之後,還需要將圖像繪制到畫布上。Canvas類可以用來實現各種圖形的繪制工作,如繪制直線、矩形、圓等等。Canvas繪制常用圖形的方法如下:
繪制直線:canvas.drawLine(float startX, float startY, float stopX, float stopY, Paint paint);
繪制矩形:canvas.drawRect(float left, float top, float right, float bottom, Paint paint);
繪制圓形:canvas.drawCircle(float cx, float cy, float radius, Paint paint);
繪制字符:canvas.drawText(String text, float x, float y, Paint paint);
繪制圖形:canvas.drawBirmap(Bitmap bitmap, float left, float top, Paint paint);
Paint(畫筆)類要繪制圖形,首先得調整畫筆,按照自己的開發需要設置畫筆的相關屬性。Pain類的常用屬性設置方法如下:
setAntiAlias(); //設置畫筆的鋸齒效果 setColor(); //設置畫筆的顏色 setARGB(); //設置畫筆的A、R、G、B值 setAlpha(); //設置畫筆的Alpha值 setTextSize(); //設置字體的尺寸 setStyle(); //設置畫筆的風格(空心或實心) setStrokeWidth(); //設置空心邊框的寬度 getColor(); //獲取畫筆的顏色
自定義完View之後,一般會對外暴露一些接口,用於控制View的狀態等,或者監聽View的變化.也就是定義接口。我們的像Button的點擊事件就是這樣的原理。
經常看一些大神的博客,大多數大神開篇都輕談一些國內比較專注的事和一些身邊瑣事,以表自己心情感悟。像我這種菜雞就直接步入正題吧。畢竟這東西就這麼簡單。Android動畫效果
本文實例講解了基於基於JMail實現Android郵件發送功能,分享給大家供大家參考,具體內容如下在android上發送郵件方式:第一種:借助GMail APP客戶端,缺
繪完報表,餅圖,接下來就繪制柱形圖,柱形很容易,就是畫線和框就行了。我分別繪制一個豎向的,一個橫向的柱形圖。 效果圖如下: package com.xcl
Android用戶界面設計:基本按鈕 本文向你展示了在你的Android應用程序中創建一個簡單的Button或ImageButton控件的步驟。首先,你會