Android 自定义控件学习之一 基础知识

来源:互联网 发布:js修改font的值 编辑:程序博客网 时间:2024/06/06 18:19

基本实现 步骤
             

1、自定义View的属性

2、在View的构造方法中获得我们自定义的属性

[ 3、重写onMesure ]

4、重写onDraw

在最新的andriod studio 中,选择自定义空间,它会生成相应的attr 文件,布局文件,属性实现文件,通过这三个文件,我们就可以设计自己的控件。


[html] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. <resources>  
  2.     <declare-styleable name="MyTextView">  
  3.         <attr name="codeString" format="string" />  
  4.         <attr name="codeDimension" format="dimension" />  
  5.         <attr name="codeColor" format="color" />  
  6.         <attr name="codeDrawable" format="color|reference" />  
  7.     </declare-styleable>  
  8. </resources>  

我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:

一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。

然后在布局中声明我们的自定义View

[html] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.   
  8.     tools:context="com.selftextview.MainActivity">  
  9.   
  10.     <LinearLayout  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="wrap_content"  
  13.         android:orientation="horizontal"  
  14.         android:paddingTop="@dimen/activity_vertical_margin"  
  15.         android:id="@+id/codes_linear">  
  16.   
  17.         <LinearLayout  
  18.             android:layout_width="match_parent"  
  19.             android:layout_height="wrap_content"  
  20.             android:layout_weight="1">  
  21.   
  22.             <EditText  
  23.                 android:layout_width="match_parent"  
  24.                 android:layout_height="match_parent"  
  25.                 android:id="@+id/codes"  
  26.                 android:hint="@string/codes"  
  27.                 android:textSize="21sp"/>  
  28.   
  29.         </LinearLayout>  
  30.   
  31.         <LinearLayout  
  32.             android:layout_width="match_parent"  
  33.             android:layout_height="wrap_content"  
  34.             android:layout_weight="1"  
  35.             android:weightSum="1">  
  36.   
  37.             <com.selftextview.MyTextView  
  38.                 android:layout_width="match_parent"  
  39.                 android:layout_height="58dp"  
  40.                 android:background="#c1c7c3"  
  41.                 app:codeColor="#33b5e5"  
  42.                 app:codeDimension="24sp"  
  43.                 app:codeString="@string/codes"  
  44.              />  
  45.   
  46.         </LinearLayout>  
  47.   
  48.     </LinearLayout>  
  49.   
  50.     <Button  
  51.         android:layout_below="@id/codes_linear"  
  52.         android:layout_width="wrap_content"  
  53.         android:layout_height="wrap_content"  
  54.         android:id="@+id/sureBtn"  
  55.         android:text="@string/sure"  
  56.         />  
  57.   
  58. </RelativeLayout>  
2、在View的构造方法中,获得我们的自定义的样式

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. <span style="color:#555555;">    private Paint paint = new Paint();  
  2.     /** 
  3.      * 验证码内容 
  4.      */  
  5.     private String[] content = null;  
  6.     /** 
  7.      * 验证码图片 
  8.      */  
  9.     private Bitmap bitmap = null;  
  10.   
  11.   
  12.     private String mCodeString;  
  13.     private int mCodeColor = Color.RED;  
  14.     private float mCodeDimension = 0;  
  15.     private Drawable mCodeDrawable;  
  16.   
  17.     private TextPaint mTextPaint;  
  18.     private float mTextWidth;  
  19.     private float mTextHeight;  
  20.   
  21.     public MyTextView(Context context) {  
  22.         super(context);  
  23.         init(null0);  
  24.     }  
  25.   
  26.     public MyTextView(Context context, AttributeSet attrs) {  
  27.         super(context, attrs);  
  28.         init(attrs, 0);  
  29.     }  
  30.   
  31.     public MyTextView(Context context, AttributeSet attrs, int defStyle) {  
  32.         super(context, attrs, defStyle);  
  33.         init(attrs, defStyle);  
  34.     }  
  35.   
  36.     private void init(AttributeSet attrs, int defStyle) {  
  37.         // Load attributes  
  38.         final TypedArray a = getContext().obtainStyledAttributes(  
  39.                 attrs, R.styleable.MyTextView, defStyle, 0);  
  40.   
  41.         //mCodeString = a.getString(  
  42.         //        R.styleable.MyTextView_codeString);  
  43.   
  44.         mCodeString = randomText();  
  45.   
  46.         mCodeColor = a.getColor(  
  47.                 R.styleable.MyTextView_codeColor,  
  48.                 mCodeColor);  
  49.         // Use getDimensionPixelSize or getDimensionPixelOffset when dealing with  
  50.         // values that should fall on pixel boundaries.  
  51.         mCodeDimension = a.getDimension(  
  52.                 R.styleable.MyTextView_codeDimension,  
  53.                 mCodeDimension);  
  54.   
  55.         if (a.hasValue(R.styleable.MyTextView_codeDrawable)) {  
  56.             mCodeDrawable = a.getDrawable(  
  57.                     R.styleable.MyTextView_codeDrawable);  
  58.             mCodeDrawable.setCallback(this);  
  59.         }  
  60.   
  61.         a.recycle();  
  62.   
  63.         // Set up a default TextPaint object  
  64.         mTextPaint = new TextPaint();  
  65.         mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);  
  66.         mTextPaint.setTextAlign(Paint.Align.LEFT);  
  67.   
  68.         invalidateTextPaintAndMeasurements();  
  69.   
  70.         this.setOnClickListener(new OnClickListener() {  
  71.             @Override  
  72.             public void onClick(View v) {  
  73.                 mCodeString = randomText();  
  74.                 postInvalidate();  /</span><span style="color:#ff6666;">/通过这个方法重新绘制</span><span style="color:#555555;">  
  75.             }  
  76.         });  
  77.     }</span>  

3.绘制该View
[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. private void invalidateTextPaintAndMeasurements() {  
  2.      mTextPaint.setTextSize(mCodeDimension);  
  3.      mTextPaint.setColor(mCodeColor);  
  4.      mTextWidth = mTextPaint.measureText(mCodeString);  
  5.   
  6.      Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();  
  7.      mTextHeight = fontMetrics.bottom;  
  8.  }  
  9.   
  10.  @Override  
  11.  protected void onDraw(Canvas canvas) {  
  12.      super.onDraw(canvas);  
  13.   
  14.      // allocations per draw cycle.  
  15.      int paddingLeft = getPaddingLeft();  
  16.      int paddingTop = getPaddingTop();  
  17.      int paddingRight = getPaddingRight();  
  18.      int paddingBottom = getPaddingBottom();  
  19.   
  20.      int contentWidth = getWidth() - paddingLeft - paddingRight;  
  21.      int contentHeight = getHeight() - paddingTop - paddingBottom;  
  22.   
  23.      // Draw the text.  
  24.      canvas.drawText(mCodeString,  
  25.              paddingLeft + (contentWidth - mTextWidth) / 2,  
  26.              paddingTop + (contentHeight + mTextHeight) / 2,  
  27.              mTextPaint);  
  28.   
  29.      // Draw the example drawable on top of the text.  
  30.      if (mCodeDrawable != null) {  
  31.          mCodeDrawable.setBounds(paddingLeft, paddingTop,  
  32.                  paddingLeft + contentWidth, paddingTop + contentHeight);  
  33.          mCodeDrawable.draw(canvas);  
  34.      }  
  35.   
  36.   
  37.  }  

4.关于onmeasure 的相关介绍
     把布局文件的宽和高写成wrap_content ,会发生铺满全屏的现象。

这里是鸿洋大神写的解释

系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。

所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:

重写之前先了解MeasureSpec的specMode,一共三种类型:

EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

UNSPECIFIED:表示子布局想要多大就多大,很少使用

下面是我们重写onMeasure代码:

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
  3. {  
  4.     int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  5.     int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
  6.     int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  7.     int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
  8.     int width;  
  9.     int height ;  
  10.     if (widthMode == MeasureSpec.EXACTLY)  
  11.     {  
  12.         width = widthSize;  
  13.     } else  
  14.     {  
  15.         mPaint.setTextSize(mTitleTextSize);  
  16.         mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  
  17.         float textWidth = mBounds.width();  
  18.         int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());  
  19.         width = desired;  
  20.     }  
  21.   
  22.     if (heightMode == MeasureSpec.EXACTLY)  
  23.     {  
  24.         height = heightSize;  
  25.     } else  
  26.     {  
  27.         mPaint.setTextSize(mTitleTextSize);  
  28.         mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  
  29.         float textHeight = mBounds.height();  
  30.         int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());  
  31.         height = desired;  
  32.     }  
  33.       
  34.       
  35.   
  36.     setMeasuredDimension(width, height);  
  37. }  

通过上面的实现可以实现文字的wrap_conent
0 0
原创粉丝点击