国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android自定義View實現驗證碼

2019-12-12 05:04:40
字體:
來源:轉載
供稿:網友

本文章是基于鴻洋的Android 自定義View (一) 的一些擴展,以及對Android自定義View構造函數詳解里面內容的一些轉載。

首先我們定義一個declare-styleable標簽declare-styleable標簽的作用是給自定義控件添加自定義屬性用的例如這樣
(我們定義了文字的顏色,大小,長度,跟背景的顏色)

<declare-styleable name="CustomTitleView"> <attr name="titleColor" format="color" /> <attr name="titleSize" format="dimension" /> <attr name="titleBackground" format="color" /> <attr name="titleLenth" format="integer" /> </declare-styleable>

Android提供了自定義屬性的方法,其中的format的參數有
(reference、color、boolean、dimension、float、integer、string、fraction、enum、flag)

1.reference:資源ID:
如果設置了這個屬性那么這個屬性相當于@string|@drawable等調用資源文件的作用
2. color:
這個屬性的作用為設置顏色值8或者6位的16進制的顏色值,如設置TextView的textColor等屬性的作用相同(如#ff000設置為紅色等)
3.boolean:
這個參數的作用為設置true或者false
4.dimension:
這個參數的作用為設置尺寸值,如px、dip、dp、sp等
5.float:
這個參數的作用為設置浮點型數據
6.integer:
這個參數的作用為設置整形數據
7.string:
這個參數的作用為設置字符串數據,如TextView的text屬性
8.fraction:
這個參數的作用為設置百分比數據
9:enum:
這個參數相當于給這個attr的name屬性設置固定的參數,如線性布局的orientation屬性只能設置vertical或者horizontal
10:flag:
這個參數作用為:位或運算

一個自定義View的步驟為

1、自定義View的屬性
2、在View的構造方法中獲得我們自定義的屬性
3、重寫onMeasure
4、重寫onDraw

有的時候onMeasure方法是不用重寫的例如系統自帶組件等
然后我們定義一下需要的屬性

 //文本 private StringBuffer mTitleText; //文本的顏色 private int mTitleColor; //文本的大小 private int mTitleSize; //背景顏色 private int mBackground; //控制生成的隨機字符串長度 private int mLenth; //繪制時控制文本繪制的范圍 private Rect mBound; //畫筆 private Paint mPaint; //隨機數對象 private Random random = new Random(); //字符串邊距 private int padding_left; //隨機的值 String[] data = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};

然后我們重寫三個構造方法,我們需要注意的是

1、在代碼中直接new一個自定義View實例的時候,會調用第一個構造函數.
2、在xml布局文件中調用自定義View的時候,會調用第二個構造函數.
3、在xml布局文件中調用自定義View,并且自定義標簽中還有自定義屬性時,這里調用的還是第二個構造函數.

也就是說,系統默認只會調用Custom View的前兩個構造函數,至于第三個構造函數的調用,通常是我們自己在構造函數中主動調用的(例如,在第二個構造函數中調用第三個構造函數).
至于自定義屬性的獲取,通常是在構造函數中通過obtainStyledAttributes函數實現的。

public CustomTitleView(Context context) { this(context, null); } public CustomTitleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setOnClickListener(this); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomTitleView); int n = typedArray.getIndexCount(); for (int i = 0; i < n; i++) {  int attr = typedArray.getIndex(i);  switch (attr) {  case R.styleable.CustomTitleView_titleColor:   mTitleColor = typedArray.getColor(attr, Color.BLACK);   break;  case R.styleable.CustomTitleView_titleSize:   mTitleSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));   break;  case R.styleable.CustomTitleView_titleBackground:   mBackground = typedArray.getColor(attr, Color.BLACK);   break;  case R.styleable.CustomTitleView_titleLenth:   mLenth = typedArray.getInteger(attr, 4);   break;  } } //回收 typedArray.recycle(); mPaint = new Paint(); randomText(); mPaint.setTextSize(mTitleSize); //創建一個矩形 mBound = new Rect(); //第一個參數為要測量的文字,第二個參數為測量起始位置,第三個參數為測量的最后一個字符串的位置,第四個參數為rect對象 mPaint.getTextBounds(mTitleText.toString(), 0, mTitleText.length(), mBound); }

obtainStyledAttributes的第二個屬性為調用你剛在在attrs.xml文件里生命的declare-styleable標簽的name
然后我們重寫一下onMeasure方法,通過getMeasuredLength方法計算出寬和高

/** * 計算寬高 * * @param lenth widthMeasureSpec或heightMeasureSpec * @param isWidth true為計算寬度,false為計算高度 */ private int getMeasuredLength(int lenth, boolean isWidth) { if (isWidth) {  if (MeasureSpec.getMode(lenth) == MeasureSpec.EXACTLY) {  //設置了精確尺寸,通過MeasureSpec.getSize()獲得尺寸返回寬度  return MeasureSpec.getSize(lenth);  } else {  //設置了warp_content,則需要我們自己計算  /**   * 首先給畫筆設置文字大小   * 通過getTextBounds方法獲得繪制的Text的寬度   * 然后因為我們的自定義View只有一個text所以我們只需要getPaddingLeft()+getPaddingRight()+textwidth即可計算出顯示出view所需要最小的寬度   * 一般計算寬度為getPaddingLeft()+getPaddingRight()+自己繪畫的文字或者圖片的寬度,因為計算的是所需寬度,假設我們繪制了圖片+文字,那么就需要判斷圖片的寬度跟文字的寬度那個更大比如getPaddingLeft()+getPaddingRight()+Math.max(圖片的寬度,文字的寬度)即得出所需寬度   */  if (MeasureSpec.getMode(lenth) == MeasureSpec.AT_MOST) {   mPaint.setTextSize(mTitleSize);   mPaint.getTextBounds(mTitleText.toString(), 0, mTitleText.length(), mBound);   float textwidth = mBound.width();   int desired = (int) (getPaddingLeft() + textwidth + getPaddingRight());   return Math.min(desired,MeasureSpec.getSize(lenth));  }  } } else {  if (MeasureSpec.getMode(lenth) == MeasureSpec.EXACTLY) {  //用戶設置了精確尺寸,通過MeasureSpec.getSize()獲得尺寸返回高度  return MeasureSpec.getSize(lenth);  } else {  if (MeasureSpec.getMode(lenth) == MeasureSpec.AT_MOST) {   //設置了warp_content,則需要我們自己計算   mPaint.setTextSize(mTitleSize);   mPaint.getTextBounds(mTitleText.toString(), 0, mTitleText.length(), mBound);   float texthgeight = mBound.height();   int desired = (int) (getPaddingTop() + texthgeight + getPaddingBottom());   return Math.min(desired,MeasureSpec.getSize(lenth));  }  } } return 0; }

然后在onMeasure方法里調用

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false)); }

系統幫我們測量的高度和寬度都是MATCH_PARNET,當我們設置明確的寬度和高度時,系統幫我們測量的結果就是我們設置的結果,當我們設置為WRAP_CONTENT,或者MATCH_PARENT系統幫我們測量的結果就是MATCH_PARENT的長度。
所以,當設置了WRAP_CONTENT時,我們需要自己進行測量,即重寫onMeasure方法

重寫之前先了解MeasureSpec的specMode,一共三種類型:
EXACTLY:一般是設置了明確的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一個最大值內,一般為WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用

在這里有些初學者可能不理解getMode跟getSize的作用,首先getMode()用于判斷寬高設置的模式,獲得到之后即可判斷,例如

//xx表示widthMeasureSpec或者heightMeasureSpecif(MeasureSpec.getMode(xx)==MeasureSpec.EXACTLY){ //進入這里則代表設置了match_parent或者將控件的layout_width或layout_height指定為具體數值時如andorid:layout_width="100dp",這樣我們就可以直接通過MeasureSpec.getSize(xx)方法獲得寬或高 }else if(MeasureSpec.getMode(xx)==MeasureSpec.EXACTLY){ //進入這里代表設置了wrap_content,那么則需要我們自己計算寬或高}else{ //進入這個則代表代表是未指定尺寸,這種情況不多,一般都是父控件是AdapterView,通過measure方法傳入的模式}

然后我們重寫一下onDraw方法、

 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); padding_left = 0; mPaint.setColor(mBackground); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); mPaint.setColor(mTitleColor); for (int i = 0; i < mTitleText.length(); i++) {  randomTextStyle(mPaint);  padding_left += mPaint.measureText(String.valueOf(mTitleText.charAt(i)))+10;  canvas.drawText(String.valueOf(mTitleText.charAt(i)), padding_left, getHeight() / 2 + mBound.height() / 2, mPaint); } }private void randomTextStyle(Paint paint) { paint.setFakeBoldText(random.nextBoolean()); //true為粗體,false為非粗體 float skewX = random.nextInt(11) / 10; skewX = random.nextBoolean() ? skewX : -skewX; paint.setTextSkewX(skewX); //float類型參數,負數表示右斜,整數左斜 paint.setUnderlineText(true); //true為下劃線,false為非下劃線 paint.setStrikeThruText(false); //true為刪除線,false為非刪除線 }

這里繪制了多個字符串,并且使每個繪制的字符串都歪歪扭扭的,這樣我們采用randomTextStyle()即可在每次繪制字符的時候設置每個字符都為不同的樣式,在這里我們講一下drawText的幾個參數,第一個參數就是要繪制的文字內容,第二個參數為x軸,作用相當于左邊距,第三個參數為Y軸,第四個參數為paint的實例,我的朋友具體講了一下drawText的繪制坐標有興趣的可以去看一下android canvas drawText()文字居中

最后我們在布局文件中引用我們的自定義view

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cq="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <chapter.com.rxjavachapter.CustomTitleView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:padding="10dp" cq:titleBackground="@android:color/black" cq:titleColor="#ff0000" cq:titleLenth="4" cq:titleSize="10sp" /></RelativeLayout>

在根布局添加 xmlns:xx=”http://schemas.android.com/apk/res-auto” 這里的xx可以是任何字母
然后用xx去點我們在attr的name去設值,最后實現出的效果是這樣

既然是驗證碼view,那么我們自然要開放出點擊改變驗證碼內容的點擊事件,在第三個構造方法中添加click事件

 @Override public void onClick(View v) { randomText(); postInvalidate(); }/** * 獲得隨機的字符串 * * @return */ private void randomText() { mTitleText = new StringBuffer(); for (int i = 0; i < mLenth; i++) {  mTitleText.append(data[(int) (Math.random() * data.length)]); } } /** * 獲得到隨機的值 * * @return */ public String getCode() { return mTitleText.toString(); } /** * 判斷是否相同 * * @return */ public boolean isEqual(String code) { if (code != null) {  return code.toUpperCase().equals(getCode().toUpperCase()) ? true : false; } else {  return false; } }

這樣就可以點擊改變一次驗證碼內容了,并且我們開放出兩個方法作為判斷驗證碼或得到驗證碼,我這只是簡單的一個驗證碼,大家可以自己加入更多的東西。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阿拉善左旗| 赞皇县| 鄂托克旗| 昭平县| 汝州市| 旅游| 吴桥县| 新龙县| 舟曲县| 景洪市| 凤翔县| 萝北县| 峨眉山市| 安徽省| 新密市| 乐清市| 湟中县| 综艺| 雅安市| 津市市| 正宁县| 钟山县| 齐齐哈尔市| 临颍县| 龙州县| 石柱| 普陀区| 蒲江县| 沙坪坝区| 克拉玛依市| 烟台市| 贵阳市| 福清市| 岱山县| 左权县| 佛冈县| 屏边| 屏边| 鄂伦春自治旗| 织金县| 白玉县|