@ZeroGeek
2015-08-19T06:13:45.000000Z
字数 10212
阅读 924
view android
http://developer.android.com/intl/zh-cn/reference/android/graphics/Canvas.html
http://developer.android.com/intl/zh-cn/reference/android/graphics/Paint.html
结合官网详细学习一遍Canvas和Paint的用法,再做一个验证码生成器
提供绘制几何图形,文本,位图的样式和颜色。
- Paint()
- Paint(int flags) flags涉及一些图形学概念,如锯齿,抖动,平滑等绘制效果
- Paint(Paint paint)
通常我们使用第一种就好
重头戏(这里我没一一列举,列举一些常用的,详细自行查阅)
- void clearShadowLayer() //清除阴影层
- int getAlpha()
- int getColor()
- boolean getFillPath(Path src, Path dst)
- int getFlags()
- int getHinting()
- PathEffect getPathEffect()
- Paint.Style getStyle()
- Paint.Align getTextAlign()
- void getTextBounds(char[] text, int index, int count, Rect bounds)
- void getTextBounds(String text, int start, int end, Rect bounds)
- void getTextPath(char[] text, int index, int count, float x, float y, Path path)
- int getTextWidths(String text, int start, int end, float[] widths)
- void reset()
- void set(Paint src)
- void setARGB(int a, int r, int g, int b)
- void setAlpha(int a)
- void setColor(int color)
- void setFlags(int flags)
- void setHinting(int mode)
- void setStyle(Paint.Style style)
看着看着就不想翻译了=。= ! 建议先去复习下计算机图形学...
参考 : http://www.cnblogs.com/angeldevil/p/3479431.html
如果在Code中实例化一个View会调用第一个构造函数,如果在xml中定义会调用第二个构造函数,而第三个函数系统是不调用的,要由View显式调用,比如我们可以在第二个构造函数中调用了第三个构造函数。
第三个参数的意义就如同它的名字所说的,是默认的Style,只是这里没有说清楚,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style。
参考:http://blog.csdn.net/lmj623565791/article/details/24252901
首先贴出核心的代码,重要地方都标有注释:
package com.zero.apptest;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Point;import android.graphics.Rect;import android.util.AttributeSet;import android.util.Log;import android.util.TypedValue;import android.view.View;import java.util.ArrayList;import java.util.List;/*** 生成数字验证码* Created by zero on 15-8-18.*/public class RandomView extends View implements View.OnClickListener{private static final String TAG = "RandomView";private String mTitleText; //验证码内容private int mTitleTextColor; //验证码数字颜色private int mTitleTextSize; //数字大小private Rect mBound; //内容大小private Paint mPaint;public static final int LEVEL_NO = 0;public static final int LEVEL_ONE = 1;public static final int LEVEL_TWO = 2;private int mNumber; //验证码数字个数private int mLevel; //识别度public RandomView(Context context,AttributeSet attrs) {this(context, attrs, 0);}public RandomView(Context context) {this(context,null);}/*** 获得自定义样式属性*/public RandomView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//设置默认属性mNumber = 4;mLevel = LEVEL_ONE;//读取自定义属性TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,R.styleable.RandomView, defStyleAttr, 0);int n = typedArray.getIndexCount();//遍历所有属性for (int i = 0; i < n; i++) {int attr = typedArray.getIndex(i);switch (attr) {case R.styleable.RandomView_myText:mTitleText = typedArray.getString(attr);break;case R.styleable.RandomView_myTextColor:mTitleTextColor = typedArray.getColor(attr, Color.BLACK); // 设置默认颜色break;case R.styleable.RandomView_myTextSize://默认设置为16sp,TypeValue可以把sp转化为pxmTitleTextSize = typedArray.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));break;}}typedArray.recycle(); //需要回收mPaint = new Paint();mPaint.setTextSize(mTitleTextSize);mBound = new Rect();mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);setOnClickListener(this); //注意绑定监听点击事件}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//分宽,高来测量,先学习三种模式MeasureSpec.EXACTLY,MeasureSpec.AT_MOST,MeasureSpec.UNSPECIFIEDint widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int width;int height ;if (widthMode == MeasureSpec.EXACTLY) {width = widthSize;} else {mPaint.setTextSize(mTitleTextSize);mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);float textWidth = mBound.width();int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());width = desired;}if (heightMode == MeasureSpec.EXACTLY) {height = heightSize;} else {mPaint.setTextSize(mTitleTextSize);mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);float textHeight = mBound.height();int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());height = desired;}//注意必须设置setMeasuredDimension(width, height);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);final float textWith = mBound.width();final float textHeight = mBound.height();final int width = getMeasuredWidth();final int height = getMeasuredHeight();mPaint.setColor(Color.parseColor("#BDC3C7"));canvas.drawRect(0, 0, width, height, mPaint);mPaint.setColor(mTitleTextColor);canvas.drawText(mTitleText, width / 2 - textWith / 2, height / 2 + textHeight / 2, mPaint);switch (mLevel) {case LEVEL_NO:break;case LEVEL_ONE:paintComplex(20,20,width,height,canvas);break;case LEVEL_TWO:paintComplex(40,40,width,height,canvas);break;default:break;}}@Overridepublic void onClick(View v) {mTitleText = getRandomNumbers(mNumber);requestLayout(); //请求重新设置布局调用onMeasure()invalidate(); //请求重绘,调用onDraw()}public void setNumber(int number) {if (number > 0 && number < 10) {mNumber = number;}}/*** 生成n位的数字串* @param n* @return*/private String getRandomNumbers(int n) {String str = " ";for (int i = 0; i < n; i++) {str += (int)(Math.random()*10);}Log.d(TAG,"str="+str);return str.trim();}//得到小于10的随机正整数private int getRandomTen() {return (int)(Math.random()*10);}/*** 设置验证码识别度* @param level*/public void setLevel(int level) {if (level == LEVEL_NO) {mLevel = LEVEL_NO;} else if (level == LEVEL_ONE) {mLevel = LEVEL_ONE;} else if (level == LEVEL_TWO) {mLevel = LEVEL_TWO;} else {mLevel = LEVEL_ONE; //默认样式}}/***获得在宽w,高h矩形中随机n个点*/private List<Point> getRandomPoint(int n, int w, int h) {List<Point> list = new ArrayList<>();for (int i = 0; i < n; i++ ) {int x = (int)(Math.random()*1000) % w;int y = (int)(Math.random()*1000) % h;Point point = new Point(x,y);list.add(point);}return list;}/*** 画上一些散落的圆点和线段*/private void paintComplex (int circleTotal,int lineTotal,int width,int height,Canvas canvas) {List<Point> circles= getRandomPoint(circleTotal,width,height); //得到15个圆心mPaint.setColor(Color.parseColor("#34495E"));for (int i = 0 ; i < circles.size() ; i++) {canvas.drawCircle(circles.get(i).x,circles.get(i).y,4,mPaint);}List<Point> lines= getRandomPoint(lineTotal,width,height); //得到10个点,作为弧的左顶点mPaint.setColor(Color.GREEN);for (int i = 0 ; i < lines.size() ; i++) {int x = lines.get(i).x;int y = lines.get(i).y;canvas.drawLine(x,y,x+getRandomTen(),y+getRandomTen(),mPaint);}}}
在res/value/下创建attrs.xml,设置自定义属性:
<?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="RandomView" ><attr name="myText" format="string" /><attr name="myTextColor" format="color" /><attr name="myTextSize" format="dimension" /></declare-styleable></resources>
main.xml :
注意 引入 xmlns:test="http://schemas.android.com/apk/res-auto" (在gradle构建下),
如果是在eclipse则引入xmlns:test="http://schemas.android.com/apk/res/<包名>"
其中 ‘test’ ,是自己取个名字,与下面定义保持一致就行。
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:test="http://schemas.android.com/apk/res-auto"xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><android.support.design.widget.TextInputLayoutandroid:id="@+id/textInput"android:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:textColor="@android:color/black"/></android.support.design.widget.TextInputLayout><Spinnerandroid:id="@+id/spinner"android:layout_width="match_parent"android:layout_height="80dp"></Spinner><Buttonandroid:id="@+id/btn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Go"/><com.zero.apptest.RandomViewandroid:id="@+id/random"android:layout_width="wrap_content"android:layout_height="50dp"test:myText="6890"test:myTextColor="#ECF0F1"test:myTextSize="26sp"android:layout_gravity="center"android:paddingLeft="5dp"android:paddingRight="5dp"/></LinearLayout>
然后是MainActivity中,主要代码
RandomView mRandomView;TextInputLayout mTIL;EditText mEt;Button mBtn;Spinner mSpinner;int mLevel;private static final String[] mRes={"无效果","等级1","等级2"};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mLevel = RandomView.LEVEL_ONE;mRandomView = (RandomView) findViewById(R.id.random);mTIL = (TextInputLayout) findViewById(R.id.textInput);mBtn = (Button) findViewById(R.id.btn);mSpinner = (Spinner) findViewById(R.id.spinner);mTIL.setHint("请输入验证码个数:");mEt = mTIL.getEditText();mEt.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {if (!isNumeric(s.toString())) {mTIL.setErrorEnabled(true);mTIL.setError("只能输入数字");mBtn.setEnabled(false);} else {mTIL.setErrorEnabled(false);mBtn.setEnabled(true);}}@Overridepublic void afterTextChanged(Editable s) {}});ArrayAdapter<String> adapter = new ArrayAdapter<>(this,android.R.layout.simple_spinner_item,mRes);adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);mSpinner.setAdapter(adapter);mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {switch (position) {case 0:mLevel = RandomView.LEVEL_NO;break;case 1:mLevel = RandomView.LEVEL_ONE;break;case 2:mLevel = RandomView.LEVEL_TWO;break;}}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});mBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String str = mEt.getText().toString().trim();if (!str.equals(null) && !str.equals("")) {int n = Integer.parseInt(str);if (n > 0 && n < 10) {mRandomView.setNumber(n);mRandomView.setLevel(mLevel);Toast.makeText(getApplicationContext(),"设置成功",Toast.LENGTH_SHORT).show();} else {closeInput();final Snackbar snackbar = Snackbar.make(mTIL,"不能超过10",Snackbar.LENGTH_LONG);snackbar.show();snackbar.setDuration(2000);snackbar.setAction("取消",new View.OnClickListener() {@Overridepublic void onClick(View v) {snackbar.dismiss();}});}}}});}private boolean isNumeric(String str) {Pattern pattern = Pattern.compile("[0-9]*");return pattern.matcher(str).matches();}private void closeInput() {InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);imm.hideSoftInputFromWindow(mTIL.getWindowToken(), 0);}
运行效果:
