27 自定义View 和案例
有时安卓提供的View不满足我们的需求时可以创建一个类继承View或其子类重写方法
- 如
package com.qf.sxy.day28_customview.view; import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View; /**
* Created by sxy on 2016/9/28.
*/
public class MyTextView extends View {
/**
* 在逻辑代码中使用
* @param context
*/
public MyTextView(Context context) {
super(context);
} /**
* 布局文件中使用 note:布局中使用必须有俩个参数
* @param context
* @param attrs 布局中设置的属性
*/
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
} /**
* @param context
* @param attrs 布局中设置的属性
* @param defStyleAttr 指定样式资源
*/
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} /**
* 绘制的方法
* @param canvas 画布
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); //创建画笔对象
Paint paint = new Paint();
paint.setColor(Color.BLUE);
// paint.setColor(0xff00);//0x 红 绿 蓝
paint.setStrokeWidth(3);//设置画笔粗细
paint.setAntiAlias(true);//抗锯齿 边缘柔和
paint.setTextSize(30);//设置文字大小
paint.setStyle(Paint.Style.STROKE);//设置样式 空心
/**
* 画直线
* 参数1:x轴起始位置
* 参数2:y轴起始位置
* 参数3:x轴终止位置
* 参数4:y轴终止位置
* 参数5:画笔对象
*/
canvas.drawLine(0,0,getWidth(),getHeight(),paint); /**
* 画圆
* 参数1,2:圆心
* 参数3:半径
* 参数4:画笔
*/
canvas.drawCircle(200,200,100,paint); /**
* 画文字
* 参数1:内容
* 参数2,3:起始位置
* 参数4:画笔
*/
canvas.drawText("国庆快乐",0,100,paint); /**
* 画图片
*/
// canvas.drawBitmap();
/**
* 画矩阵
*/
// canvas.clipRect() //....
}
}
在使用此自定义View的时候在布局文件 写完整的包名类名
如
<!--
使用自定义View 包名+类名
-->
<com.qf.sxy.day28_customview.view.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
如果我们想在布局文件中设置属性的话 那么可以按一下步骤
- 在valus文件夹新建一个resources文件
如
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
circleColor 圆的颜色
sweepColor 扫描的颜色
startAngle 起始角度
sweepAngle 扫描角度
sweepStep 每次扫描的步数
-->
<declare-styleable name="ProgressView">
<attr name="circleColor" format="color|reference"></attr>
<attr name="sweepColor" format="color|reference"></attr>
<attr name="startAngle" format="integer|reference"></attr>
<attr name="sweepAngle" format="integer|reference"></attr>
<attr name="sweepStep" format="integer|reference"></attr>
</declare-styleable>
</resources>赋值方法
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context="com.qf.sxy.customview3.MainActivity"> <com.qf.sxy.customview3.widget.ProgressView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:circleColor="#00ff00"
app:sweepColor="#0000ff"
app:sweepStep="10"
app:sweepAngle="0"
app:startAngle="0"
/>
<com.qf.sxy.customview3.widget.ProgressView
android:layout_width="200dp"
android:layout_height="200dp"
app:circleColor="#0000ff"
app:sweepColor="#ff00ff"
app:sweepStep="2"
app:startAngle="-90"
/>
<com.qf.sxy.customview3.widget.ProgressView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:circleColor="#00ffff"
app:sweepColor="#005644"
app:sweepStep="20"
app:startAngle="180"
/>
</LinearLayout>
获取属性值
public ProgressView(Context context) {
this(context,null);
} public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
//获取布局中属性
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.ProgressView);
if(array!=null){
circleColor = array.getColor(R.styleable.ProgressView_circleColor,Color.BLUE);
sweepColor = array.getColor(R.styleable.ProgressView_sweepColor,Color.RED);
startAngle = array.getInteger(R.styleable.ProgressView_startAngle,-90);
sweepStep = array.getInteger(R.styleable.ProgressView_sweepStep,1);
} }
具体案例一
一个最基础的案例 继承一个View画一个圆等
- 重写View文件MyTextView.java
package com.qf.sxy.day28_customview.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by sxy on 2016/9/28.
*/
public class MyTextView extends View {
/**
* 在逻辑代码中使用
* @param context
*/
public MyTextView(Context context) {
super(context);
}
/**
* 布局文件中使用 note:布局中使用必须有俩个参数
* @param context
* @param attrs 布局中设置的属性
*/
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* @param context
* @param attrs 布局中设置的属性
* @param defStyleAttr 指定样式资源
*/
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 绘制的方法
* @param canvas 画布
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//创建画笔对象
Paint paint = new Paint();
paint.setColor(Color.BLUE);
// paint.setColor(0xff00);//0x 红 绿 蓝
paint.setStrokeWidth(3);//设置画笔粗细
paint.setAntiAlias(true);//抗锯齿 边缘柔和
paint.setTextSize(30);//设置文字大小
paint.setStyle(Paint.Style.STROKE);//设置样式 空心
/**
* 画直线
* 参数1:x轴起始位置
* 参数2:y轴起始位置
* 参数3:x轴终止位置
* 参数4:y轴终止位置
* 参数5:画笔对象
*/
canvas.drawLine(0,0,getWidth(),getHeight(),paint);
/**
* 画圆
* 参数1,2:圆心
* 参数3:半径
* 参数4:画笔
*/
canvas.drawCircle(200,200,100,paint);
/**
* 画文字
* 参数1:内容
* 参数2,3:起始位置
* 参数4:画笔
*/
canvas.drawText("国庆快乐",0,100,paint);
/**
* 画图片
*/
// canvas.drawBitmap();
/**
* 画矩阵
*/
// canvas.clipRect()
//....
}
}
布局文件activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.qf.sxy.day28_customview.MainActivity">
<!--
使用自定义View 包名+类名
-->
<com.qf.sxy.day28_customview.view.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
具体案例二
说明
展示如何设置属性 然后在布局文件里面赋值 和在重写类获取对应属性值
(重写View方法的类)MyTextView.java
package com.qf.sxy.customview02.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import com.qf.sxy.customview02.R;
/**
* Created by sxy on 2016/9/28.
*/
public class MyTextView extends View {
TextView tv;
private Paint mPaint;
private String mText="哈哈";
public MyTextView(Context context) {
super(context);
initPain();
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initPain();
//获取布局资源中的属性
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyTextView);
//获取文本内容
CharSequence ch = array.getText(R.styleable.MyTextView_text);
if(ch!=null&&!"".equals(ch)){
setText(ch.toString());
}
//获取文本颜色
int textColor = array.getColor(R.styleable.MyTextView_textColor,Color.BLACK);
settextColor(textColor);
//获取字体大小
int textSize = (int)(array.getDimension(R.styleable.MyTextView_textSize,30));
setTextSize(textSize);
}
//设置字体大小
private void setTextSize(int textSize) {
mPaint.setTextSize(textSize);
requestLayout();//重新绘制画布 会
invalidate();//进行刷新(重新获取数据)
}
//设置文本颜色
public void settextColor(int textColor) {
mPaint.setColor(textColor);
requestLayout();//重新绘制画布
invalidate();//进行刷新(重新获取数据)
}
//给文本设置内容
private void setText(String str) {
mText = str;
//onMeasure只会重新调用次方
requestLayout();//重新绘制画布
//重新调用ondraw方法 和上诉方法正好相反
invalidate();//进行刷新(重新获取数据)
}
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPain();
}
//初始化画笔对象
public void initPain() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setAntiAlias(true);
mPaint.setTextSize(30);
//设置文字的内边距
setPadding(10,10,10,10);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//给画布设置颜色
canvas.drawColor(Color.GREEN);
canvas.drawText(mText,getPaddingLeft(),getPaddingTop()-mPaint.ascent(),mPaint);
}
/**
* 测量控件大小
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// //得到设置的模式
// int wMode = MeasureSpec.getMode(widthMeasureSpec);
// //获取父布局的宽高/50dp
// int wSize = MeasureSpec.getSize(widthMeasureSpec);
//
// /**
// * MeasureSpec.UNSPECIFIED:Adapter View用到 未设定尺寸
// * MeasureSpec.AT_MOST:wrap_content 根据里面内容变化而变化
// * MeasureSpec.EXACTLY:match_parent/50dp 精准的值
// */
//
// if(wMode == MeasureSpec.AT_MOST){//wrap_content 根据里面内容变化而变化
// //获取宽 计算
//
// }else if(wMode == MeasureSpec.EXACTLY){ //match_parent/50dp 精准的值
// //wSize
// }
//设定最终的宽和高
setMeasuredDimension(Measure(widthMeasureSpec,1),Measure(heightMeasureSpec,2));
}
//进行测量
public int Measure(int Spec ,int type){
int result=0;//返回的值
int mode = MeasureSpec.getMode(Spec);
int size = MeasureSpec.getSize(Spec);
if(mode == MeasureSpec.AT_MOST){//wrap_content 根据里面内容变化而变化
//计算
if(type==1){//获取宽 左右内边距+文字宽
result = (int)(getPaddingLeft()+getPaddingRight()+mPaint.measureText(mText));
}else if(type==2){//获取高
result = (int)(getPaddingTop()+getPaddingBottom()+mPaint.descent()-mPaint.ascent());
}
}else if(mode == MeasureSpec.EXACTLY){ //match_parent/50dp 精准的值
//wSize
result = size;
}
return result;
}
}
设置属性文件attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
<declare-styleable name="样式名称">
name ="名称" format="类型"
string 字符串
reference 引用的类型 R.string.xxx
dimension 尺寸
color 颜色
<attr name="text" format="string|reference"></attr>
</declare-styleable>
-->
<declare-styleable name="MyTextView">
<attr name="text" format="string|reference"></attr>
<!--dimension可以在此属性写 XXXDP或者XXXDIP-->
<attr name="textSize" format="dimension|reference"></attr>
<attr name="textColor" format="color|reference"></attr>
</declare-styleable>
</resources>
activity_main.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.qf.sxy.customview02.MainActivity">
<!--
命名空间 引用资源的
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/包名"
-->
<com.qf.sxy.customview02.widget.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:text="国庆快乐"
app:textSize="20sp"
app:textColor="#ff00ff"
/>
</RelativeLayout>
案例三
说明 在界面画一个圆 然后让其一直旋转 360APP的雷达效果
ProgressView.java(重写View方法)
package com.qf.sxy.customview3.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import com.qf.sxy.customview3.R;
/**
* Created by sxy on 2016/9/28.
*/
public class ProgressView extends View {
private int circleColor = Color.BLUE;//设置颜色
private int startAngle = -90;//开始的角度
private int sweepAngle = 0;//扫描的角度
private int sweepStep = 5;//每次扫描走多少
private int sweepColor = Color.RED;
//wrap_content 设定宽高 100
int sweepWith =100;
int sweepHeight =100;
public ProgressView(Context context) {
this(context,null);
}
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
//获取布局中属性
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.ProgressView);
if(array!=null){
circleColor = array.getColor(R.styleable.ProgressView_circleColor,Color.BLUE);
sweepColor = array.getColor(R.styleable.ProgressView_sweepColor,Color.RED);
startAngle = array.getInteger(R.styleable.ProgressView_startAngle,-90);
sweepStep = array.getInteger(R.styleable.ProgressView_sweepStep,1);
}
}
/**
* 绘制
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(circleColor);
paint.setAntiAlias(true);
//绘制圆 控件的一半
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,paint);
//重新设置画笔颜色
paint.setColor(sweepColor);
//绘制的扇形
canvas.drawArc(new RectF(0,0,getWidth(),getHeight()),startAngle,sweepAngle,true,paint);
sweepAngle += sweepStep;//扫描角度等于 走的和
sweepAngle= sweepAngle>360?0:sweepAngle;//是否跑了一圈
invalidate();//刷新数据
}
/**
* 测量
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int wMode = MeasureSpec.getMode(widthMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
int wSize = MeasureSpec.getSize(widthMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec);
switch (wMode){
case MeasureSpec.AT_MOST:
// wSize = sweepWith;
wSize = hSize = sweepHeight;
break;
case MeasureSpec.EXACTLY:
wSize = hSize = Math.min(wSize,hSize);
break;
}
//设置最终的宽高
setMeasuredDimension(wSize,hSize);
}
}
属性文件attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
circleColor 圆的颜色
sweepColor 扫描的颜色
startAngle 起始角度
sweepAngle 扫描角度
sweepStep 每次扫描的步数
-->
<declare-styleable name="ProgressView">
<attr name="circleColor" format="color|reference"></attr>
<attr name="sweepColor" format="color|reference"></attr>
<attr name="startAngle" format="integer|reference"></attr>
<attr name="sweepAngle" format="integer|reference"></attr>
<attr name="sweepStep" format="integer|reference"></attr>
</declare-styleable>
</resources>
布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context="com.qf.sxy.customview3.MainActivity">
<com.qf.sxy.customview3.widget.ProgressView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:circleColor="#00ff00"
app:sweepColor="#0000ff"
app:sweepStep="10"
app:sweepAngle="0"
app:startAngle="0"
/>
<com.qf.sxy.customview3.widget.ProgressView
android:layout_width="200dp"
android:layout_height="200dp"
app:circleColor="#0000ff"
app:sweepColor="#ff00ff"
app:sweepStep="2"
app:startAngle="-90"
/>
<com.qf.sxy.customview3.widget.ProgressView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:circleColor="#00ffff"
app:sweepColor="#005644"
app:sweepStep="20"
app:startAngle="180"
/>
</LinearLayout>
案例四
继承View 并实现监听方法 当用户点击时View中的数字+1
重写View的类CountView.java
package com.qf.sxy.customview04;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by sxy on 2016/9/28.
*/
public class CountView extends View implements View.OnClickListener{
private Paint mPaint;
private int count =0;
public CountView(Context context) {
this(context,null);
}
public CountView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CountView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化化画笔对象
initPaint();
//监听事件
setOnClickListener(this);
}
private void initPaint(){
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setTextSize(300);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取当前的数字字符串
String countStr =String.valueOf(count);
Rect rect = new Rect();
//获取文字区域
mPaint.getTextBounds(countStr,0,countStr.length(),rect);
int strWith = rect.width();
int strHeight = rect.height();
canvas.drawText(countStr,getWidth()/2-strWith/2,getHeight()/2+strHeight/2,mPaint);
}
//点击事件的监听
@Override
public void onClick(View v) {
count++;
invalidate();//刷新
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.qf.sxy.customview04.MainActivity">
<com.qf.sxy.customview04.CountView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
案例五
说明 View上有一个点 当用户点击或者移动时小点变色并且跟随移动
重写View的类BallView.java
package com.qf.sxy.customview05.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.Random;
/**
* Created by sxy on 2016/9/28.
*/
public class BallView extends View {
private Paint mPaint;
private int cx = 50,cy=50,radius = 20;//圆心x 圆心y 半径
//小球颜色随机改变
private int[] colors = {Color.BLACK,Color.BLUE,Color.DKGRAY,Color.GREEN,Color.RED,Color.YELLOW};
private int pWith = 100,pHeight =100;
public BallView(Context context) {
this(context,null);
}
public BallView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public BallView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化画笔对象
initPaint();
}
private void initPaint(){
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
}
//绘制 小球
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//是否出界
isOutSide();
//随机获取颜色
getBallColor();
//绘制一个小球
canvas.drawCircle(cx,cy,radius,mPaint);
}
private void isOutSide() {
if(cx<radius){//左
cx = radius;
}
if(cx>pWith-radius){//右
cx = pWith-radius;
}
if(cy<radius){//上
cy = radius;
}
if(cy>pHeight-radius){//下
cy = pHeight-radius;
}
}
private void getBallColor() {
Random r = new Random();
int color = r.nextInt(colors.length);
mPaint.setColor(colors[color]);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN://按下事件
cx = (int)event.getX();
cy = (int)event.getY();
invalidate();//刷新
break;
case MotionEvent.ACTION_MOVE://移动事件
cx = (int)event.getX();
cy = (int)event.getY();
invalidate();//刷新
break;
case MotionEvent.ACTION_UP://抬起的事件
cx = (int)event.getX();
cy = (int)event.getY();
invalidate();//刷新
break;
}
//消费事件 不然会有问题
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
pWith = MeasureSpec.getSize(widthMeasureSpec);
pHeight = MeasureSpec.getSize(heightMeasureSpec);
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.qf.sxy.customview05.MainActivity">
<com.qf.sxy.customview05.widget.BallView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
案例6
说明 重写EditText 并监听文本改变事件 如果有字就在文本框右侧改变图片
MyEditText.java
package com.qf.sxy.customview06.widget;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.widget.EditText;
import com.qf.sxy.customview06.R;
/**
* Created by sxy on 2016/9/28.
*/
public class MyEditText extends EditText {
Drawable drawable1;
Drawable drawable2;
public MyEditText(Context context) {
this(context,null);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
changeBitmap();
}
public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//根据文本输入 修改图片
// changeBitmap();
}
public void changeBitmap(){
addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//修改图片
setBitmap();
}
@Override
public void afterTextChanged(Editable s) {
}
});
setBitmap();
}
//设置图片
public void setBitmap(){
drawable1 =getResources().getDrawable(R.mipmap.ic_launcher);
drawable2 =getResources().getDrawable(R.mipmap.qq);
if(length()>0){//设置一种图片
// setFocusable(true);
//左上右下
setCompoundDrawablesWithIntrinsicBounds(null,null,drawable1,null);
}else{//设置另一种图片
// setFocusable(true);
//左上右下
setCompoundDrawablesWithIntrinsicBounds(null,null,drawable2,null);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.qf.sxy.customview06.MainActivity">
<com.qf.sxy.customview06.widget.MyEditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:enabled="true"
android:hint="请输入姓名" />
<com.qf.sxy.customview06.widget.MyEditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入密码"
/>
</LinearLayout>
案例7
说明 继承EditText 设置一张背景图 并且划线 让其想一个笔记本
MyNoteView.java
package com.qf.sxy.customview07.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.EditText;
import com.qf.sxy.customview07.R;
/**
* Created by sxy on 2016/9/28.
*/
public class MyNoteView extends EditText {
private int lineSpace = 50;//行间距
private Paint mPaint ;
private int linePadding = 60;//设置内边距
private int lineColor = Color.RED;
public MyNoteView(Context context) {
super(context);
}
public MyNoteView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化画笔对象
initPaint();
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyNoteView);
if(array!=null){
lineColor = array.getColor(R.styleable.MyNoteView_lineColor,Color.RED);
linePadding = array.getInteger(R.styleable.MyNoteView_linePadding,60);
lineSpace = array.getInteger(R.styleable.MyNoteView_lineSpace,60);
}
mPaint.setColor(lineColor);
//设置行间距 参数1:间距 参数2:倍数
setLineSpacing(lineSpace,1);
//设置整个的内边距
setPadding(linePadding,0,linePadding,0);
//文字从顶部开始
setGravity(Gravity.TOP);
}
public void initPaint(){
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
}
//绘制线
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取View的高度
int height = getHeight();
//获取每一行的高度
int lineHeight = getLineHeight();
//得到总的线的数量
int lineNum = height/lineHeight;
for(int i=0;i<lineNum;i++){
canvas.drawLine(linePadding,(i+1)*lineHeight,getWidth()-linePadding,(i+1)*lineHeight,mPaint);
}
//获取文本行数
int linesCount = getLineCount();
//画多余的部分
for(int i = lineNum;i<linesCount;i++ ){
canvas.drawLine(linePadding,i*lineHeight,getWidth()-linePadding,i*lineHeight,mPaint);
}
}
}
属性文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyNoteView">
<attr name="lineSpace" format="integer|reference"></attr>
<attr name="linePadding" format="integer|reference"></attr>
<attr name="lineColor" format="color|reference"></attr>
</declare-styleable>
</resources>
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.qf.sxy.customview07.MainActivity">
<com.qf.sxy.customview07.widget.MyNoteView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/background"
app:lineColor="#0000ff"
app:linePadding="100"
app:lineSpace="30"
/>
</RelativeLayout>
27 自定义View 和案例的更多相关文章
- Android简易实战教程--第二十七话《自定义View入门案例之开关按钮详细分析》
转载此博客请注明出处点击打开链接 http://blog.csdn.net/qq_32059827/article/details/52444145 对于自定义view,可能是一个比较大的 ...
- 27 自定义View小结
自定义View 1 为了满足开发需要 就需要自定义View 2 分类: 直接继承View 继承View的子类(现有控件 button,TextView-.) 继承ViewGroup(线性布局 相对布局 ...
- 【朝花夕拾】Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/10998855.html]谢谢! 在自定义View中,经常需要处理Android事件分发的问题, ...
- 【朝花夕拾】Android自定义View篇之(一)View绘制流程
前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...
- Android之自定义View的实现
对于学习Android开发的小童鞋对于自定义View一定不会陌生,相信大家对它是又爱又恨,爱它可以跟随我们的心意设计出漂亮的效果:恨它想要完全流畅掌握,需要一定的功夫.对于初学者来说确实很不容易,网上 ...
- Android自定义View的三种实现方式
在毕设项目中多处用到自定义控件,一直打算总结一下自定义控件的实现方式,今天就来总结一下吧.在此之前学习了郭霖大神博客上面关于自定义View的几篇博文,感觉受益良多,本文中就参考了其中的一些内容. 总结 ...
- Android 自定义View 三板斧之三——重写View来实现全新控件
通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文来讨论最难的一种 ...
- Android 自定义View及其在布局文件中的使用示例(三):结合Android 4.4.2_r1源码分析onMeasure过程
转载请注明出处 http://www.cnblogs.com/crashmaker/p/3549365.html From crash_coder linguowu linguowu0622@gami ...
- 自定义View和ViewGroup
为了扫除学习中的盲点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容上面并没有什么独特的地方,其他大神们的博客上面基本上都有讲这方面的内容,如 ...
随机推荐
- leetcode 717. 1-bit and 2-bit Characters -easy
https://leetcode.com/problems/1-bit-and-2-bit-characters/description/ We have two special characters ...
- [LeetCode] Find Duplicate File in System 在系统中寻找重复文件
Given a list of directory info including directory path, and all the files with contents in this dir ...
- tkinter 创建登陆注册界面
import tkinter as tk from tkinter import messagebox #设置窗口居中 def window_info(): ws = window.winfo_scr ...
- webpack模块化管理和打包工具
Webpack简介 webpack是当下最热门的前端资源模块化管理和打包工具.它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源.还可以将按需加载的模块进行代码分隔,等到实际 需要的 ...
- [NOIp 2012]同余方程
Description 求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. Input 输入只有一行,包含两个正整数 a, b,用一个空格隔开. Output 输出只有一行,包含一个 ...
- [BZOJ 3332]旧试题
Description 圣诞节将至.一年一度的难题又摆在wyx面前——如何给妹纸送礼物. wyx的后宫有n人,这n人之间有着复杂的关系网,相互认识的人有m对.wyx想要量化后宫之间的亲密度,于是准备给 ...
- epoll源码分析(转)
在create后会创建eventpoll对象保存在一个匿名fd的file struct的private指针中,然后进程睡在等待队列上面. 对于等待的fd,通过poll机制在准备好之后会调用相应的cal ...
- ●BZOJ 1416 [NOI2006]神奇的口袋
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1416题解: Pòlya瓦罐模型: 给定罐子里每种颜色的球的个数A[i],按题目要求随机操作若 ...
- Linux命令-关机命令详解
关机命令:1.halt 立刻关机 2.poweroff 立刻关机 3.shutdown -h now 立刻关机(root用户使用) 4.shutdown -h 10 10分钟后自动关机 如果是通过sh ...
- jQuery Datetable 渲染
渲染器 有些情况下,使用表时,表中的行的数据源不包含您希望在表中直接显示的值.您可能希望将其转换为不同的表示形式(时间戳为人类可读的格式),合并数据点(名字和姓氏)或对该值执行一些计算(计算营业额和费 ...