android自定义控件(一) 入门
2016-06-14 16:46
465 查看
转自:鸿洋的博客,正在学习,非常感谢!
自定义View的步骤:
1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
[ 3、重写onMesure ]
4、重写onDraw
我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的。
1.自定义View的属性,首先在res/values/ 下建立一个styleable.xml , 在里面定义我们的属性和声明我们的整个样式。
我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:
一共有:
2.然后在布局中声明我们的自定义View:
**一定要引入 xmlns:custom=”http://schemas.android.com/apk/res/res-auto”我们的命名空间,后面的包路径指的是项目的package或者res-auto
**
3.自定义view代码:
现在的效果是:
很明显文字不是在中间位置,原因是:
当我们在xml中将width或者height设置成warp_content时会全屏铺展,感觉是match_parent的效果
这时的处理是在onMeasure中重新计算要绘制的宽高
首先要了解的是,我们怎么知道用户设置的width是什么样子的?
这个可以通过一个类MeasureSpec的specMode来判断
MeasureSpec的specMode有三种类型:
EXACTLY:一般是设置了明确的值或者Match_parent
AT_MOST:表示子布局限制在一个最大值内,一般是wrap_content布局
UNSPECIFIED:表示子布局想要多大就有多大,很少使用
所以当用户设置match_parent的时候就让其自动显示,除此之外我们来设置它要绘制的范围;
所以重写onMeasure:
最终效果如下:
自定义View的步骤:
1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
[ 3、重写onMesure ]
4、重写onDraw
我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的。
1.自定义View的属性,首先在res/values/ 下建立一个styleable.xml , 在里面定义我们的属性和声明我们的整个样式。
<?xml version="1.0" encoding="utf-8"?> <resources> <!--定义一些基本的属性--> <attr name="textTitle" format="string"/> <attr name="textColor" format="color"/> <attr name="textSize" format="dimension"/> <declare-styleable name="CustomeView"> <attr name="textTitle"/> <attr name="textColor"/> <attr name="textSize"/> </declare-styleable> </resources>
我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:
一共有:
string,color,demension,integer,enum,reference,float,boolean,fraction,flag;
2.然后在布局中声明我们的自定义View:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.down.customeviewdemo_1.MainActivity"> <com.example.down.customeviewdemo_1.CustomeView android:id="@+id/img" android:layout_width="100dp" android:layout_height="100dp" app:textTitle="哈哈哈哈哈哈哈哈" app:textColor="#009933" app:textSize="10sp" /> </RelativeLayout>
**一定要引入 xmlns:custom=”http://schemas.android.com/apk/res/res-auto”我们的命名空间,后面的包路径指的是项目的package或者res-auto
**
3.自定义view代码:
//画笔 Paint mPaint =null; //可视区域 Rect mRect =null; //自己定义的基本属性 private int textSize; private String textTitle; private int textColor; public void setTextColor(int textColor) { this.textColor = textColor; } public void setTextSize(int textSize) { this.textSize = textSize; } public void setTextTitle(String textTitle) { this.textTitle = textTitle; } public CustomeView(Context context) { this(context,null); } public CustomeView(Context context, AttributeSet attrs) { this(context, attrs,0); } public CustomeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //获取styleable.xml中定义的基本属性 TypedArray a=context.getTheme().obtainStyledAttributes(attrs,R.styleable.CustomeView,defStyleAttr,0); int n=a.getIndexCount(); for (int i=0;i<n;i++){ int attr=a.getIndex(i); switch (attr){ case R.styleable.CustomeView_textTitle: textTitle=a.getString(attr); break; case R.styleable.CustomeView_textColor: textColor=a.getColor(attr, Color.BLACK);//默认黑色字体 break; case R.styleable.CustomeView_textSize://这里用的是px textSize=a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));//默认16sp break; } } a.recycle();//释放回收 //基本初始化 mPaint =new Paint(); mRect =new Rect(); mPaint.setTextSize(textSize); mPaint.getTextBounds(textTitle, 0, textTitle.length(), mRect); } //计算控件的绘制位置 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } //绘制控件 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(textColor); //绘制一个rectangle显示text canvas.drawRect(0, 0, getMeasuredWidth(),getMeasuredHeight(), mPaint); //在onMeasure没有做处理的时候,+getWidth()+"-"+getMeasuredWidth()是相等的 // Log.i("yqy", "" + getWidth() + "-" + getMeasuredWidth() + "---" + getHeight() + "," + getMeasuredHeight()); //绘制text mPaint.setColor(Color.WHITE); Log.i("yqy","要绘制的文本=="+textTitle+","+textSize+","+textColor+","+getWidth()+","+getHeight()); canvas.drawText(textTitle, getWidth() / 2-mRect.width()/2 , getHeight() / 2 + mRect.height() / 2, mPaint); }
现在的效果是:
很明显文字不是在中间位置,原因是:
mPaint.setTextSize(textSize);这句话的位置,在ondraw里面就是这个样子,放在构造函数中就是显示中间位置 1.构造函数中: mPaint.setTextSize(textSize); mPaint.getTextBounds(textTitle,0,textTitle.length(),mRect); Log.i("yqy",mRect.width()+"----"+getWidth());//315----768 2.构造函数中: mPaint.getTextBounds(textTitle,0,textTitle.length(),mRect); mPaint.setTextSize(textSize); Log.i("yqy",mRect.width()+"----"+getWidth());//95----768 3.onDraw()中是一样的结果 Log.i("yqy",mRect.width()+"----"+getWidth());//95----768 总结:大小一定要在ondraw方法之前就计算好
当我们在xml中将width或者height设置成warp_content时会全屏铺展,感觉是match_parent的效果
这时的处理是在onMeasure中重新计算要绘制的宽高
首先要了解的是,我们怎么知道用户设置的width是什么样子的?
这个可以通过一个类MeasureSpec的specMode来判断
MeasureSpec的specMode有三种类型:
EXACTLY:一般是设置了明确的值或者Match_parent
AT_MOST:表示子布局限制在一个最大值内,一般是wrap_content布局
UNSPECIFIED:表示子布局想要多大就有多大,很少使用
所以当用户设置match_parent的时候就让其自动显示,除此之外我们来设置它要绘制的范围;
所以重写onMeasure:
int widthSise=MeasureSpec.getSize(widthMeasureSpec); int heightSize=MeasureSpec.getSize(heightMeasureSpec); int widthMode=MeasureSpec.getMode(widthMeasureSpec); int heightMode=MeasureSpec.getMode(heightMeasureSpec); //最终要显示的宽和高 int width; int height; if(widthMode==MeasureSpec.EXACTLY){ width=widthSise; }else{//自定义 mPaint.setTextSize(textSize); mPaint.getTextBounds(textTitle,0,textTitle.length(),mRect); width=getPaddingLeft()+mRect.width()+getPaddingRight(); } if(heightMode==MeasureSpec.EXACTLY){ height=heightSize; }else{ mPaint.setTextSize(textSize); mPaint.getTextBounds(textTitle,0,textTitle.length(),mRect); height=getPaddingTop()+mRect.height()+getPaddingBottom(); } //这句话一定要写 setMeasuredDimension(width,height);
最终效果如下:
相关文章推荐
- Android 无限循环ViewPager报错跳坑。
- FragmentTabHost类实现android中Fragment的动态加载
- android studio命令打包(gradle)
- Android 对ScrollView滚动监听,实现美团、大众点评的购买悬浮效果
- android悬浮窗口的实现
- Android 代码规范
- Android的 PackageManager 和ActivityManager的功能介绍
- Android开发中,有哪些让你觉得相见恨晚的方法、类或接口
- android( java) 处理 null 和 预防空指针异常(NullPointerException) 的一些经验。
- Android之Fragment(二):动态加载碎片
- Android音视频之MediaRecorder音视频录制
- 使用DX 编译 Android应用
- Android消息机制初步分析
- AndroidStudio引入so文件
- Android,如何在代码中获取attr属性的值
- android 获取手机通讯录以及 6.0 授权
- Android内存泄漏分析实例
- android下拉菜单spinner的使用方法
- Android中的Drawable资源—— GradientDrawable
- android开发常用快捷键