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做一个稍微全面一点的使用方法总结,在内容上面并没有什么独特的地方,其他大神们的博客上面基本上都有讲这方面的内容,如 ...
随机推荐
- vue 2.0 路由切换以及组件缓存源代码重点难点分析
摘要 关于vue 2.0源代码分析,已经有不少文档分析功能代码段比如watcher,history,vnode等,但没有一个是分析重点难点的,没有一个是分析大命题的,比如执行router.push之后 ...
- 虚拟机工作站创建虚拟机并安装Linux教程
前言: 今天开始学习一下Linux,之前早就想看,但是一直没时间,最近把其他知识整理完了,终于有时间来看一下Linux了. 本节只是安装虚拟机工作站,虚拟机,和Linux操作系统的过程,详细的记录了我 ...
- [HNOI 2018]排列
Description 题库链接 给定 \(n\) 个整数 \(a_1, a_2, \dots, a_n, 0 \le ai \le n\) ,以及 \(n\) 个整数 \(w_1, w_2, \do ...
- [NOIp 2009]靶形数独
Description 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他 ...
- tcp窗口滑动以及拥塞控制(转)
转自:http://blog.chinaunix.net/uid-26275986-id-4109679.html TCP协议作为一个可靠的面向流的传输协议,其可靠性和流量控制由滑动窗口协议保证,而拥 ...
- bzoj 4006: [JLOI2015]管道连接
Description 小铭铭最近进入了某情报部门,该部门正在被如何建立安全的通道连接困扰. 该部门有 n 个情报站,用 1 到 n 的整数编号.给出 m 对情报站 ui;vi 和费用 wi,表示情 ...
- hihocoder #1142 : 三分·三分求极值
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 这一次我们就简单一点了,题目在此: 在直角坐标系中有一条抛物线y=ax^2+bx+c和一个点P(x,y),求点P到抛物线的 ...
- git日常使用经验积累
1 git merge origin/develop 将远程分支合并到本地,一般先执行合并,解决冲突,然后再git commit合入新建的分支,推送到远程分支里面,最后码云上找pl pull requ ...
- Python3中无法导入ssl模块的解决办法
这个问题,已经困扰我好几天了,本萌新刚开始接触python,想爬取几个网页试试,发现urllib无法识别https,百度后才知道要导入ssl模块,可是发现又报错了. 本人实在无法理解为什么会报错,因为 ...
- TensorFlow Serving-TensorFlow 服务
TensorFlow服务是一个用于服务机器学习模型的开源软件库.它处理机器学习的推断方面,在培训和管理他们的生命周期后采取模型,通过高性能,引用计数的查找表为客户端提供版本化访问. 可以同时提供多个模 ...