自定义View
程序员文章站
2022-05-30 20:19:05
...
一.自定义View分类
在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View。
二.时钟案例(思路+代码)
1.新建一个类继承View(我的类名是MyView),实现Lintener接口
package com.example.weatherreport.customView;
import android.content.Context;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by lenovo on 2018/6/16.
*/
public class MyView extends View {
public MyView(Context context) {
super(context);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
}
2.重写onDraw,画圆,在布局文件中引用。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画笔
Paint paint=new Paint();
//抗锯齿
paint.setAntiAlias(true);
//染色
paint.setColor(Color.GRAY);
//画圆(圆心横坐标,圆心纵坐标,半径,画笔);
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,paint);
}
布局文件代码:
<com.example.weatherreport.customView.MyView
android:id="@+id/clock_mv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
效果如图:
3.画出指针和时间。
int hour=20;//时
int minute=20;//分
int second=0;//秒
//秒针
canvas.save();//保存当前画布
//设置指针的宽度
paint.setStrokeWidth(2);
//旋转角度(角度,起始X坐标,起始Y坐标)
canvas.rotate(second*6,getWidth()/2,getHeight()/2);
paint.setColor(Color.WHITE);
//画指针(起始位置X坐标,起始位置Y坐标,终止位置X坐标,终止位置Y坐标,画笔);
canvas.drawLine(getWidth()/2,getHeight()/2,getWidth()/2,getHeight()/2-getWidth()/2+100,paint);
canvas.restore();//恢复画布
//分针
canvas.save();//保存当前画布
//设置指针的宽度
paint.setStrokeWidth(5);
//旋转角度(角度,起始X坐标,起始Y坐标)
canvas.rotate(minute*6,getWidth()/2,getHeight()/2);
paint.setColor(Color.WHITE);
//画指针(起始位置X坐标,起始位置Y坐标,终止位置X坐标,终止位置Y坐标,画笔);
canvas.drawLine(getWidth()/2,getHeight()/2,getWidth()/2,getHeight()/2-getWidth()/2+200,paint);
canvas.restore();//恢复画布
//时针
canvas.save();//保存当前画布
//设置指针的宽度
paint.setStrokeWidth(8);
//旋转角度(角度,起始X坐标,起始Y坐标)
canvas.rotate(hour*30+minute*30/60,getWidth()/2,getHeight()/2);
paint.setColor(Color.WHITE);
//画指针(起始位置X坐标,起始位置Y坐标,终止位置X坐标,终止位置Y坐标,画笔);
canvas.drawLine(getWidth()/2,getHeight()/2,getWidth()/2,getHeight()/2-getWidth()/2+300,paint);
canvas.restore();//恢复画布
//12个刻度
for (int i=1;i<=12;i++){
canvas.save();
//字体尺寸
paint.setTextSize(50);
canvas.rotate(30*i,getWidth()/2,getHeight()/2);
//画刻度(文本内容,起始位置X坐标,起始位置Y坐标,画笔)
canvas.drawText(i+"",getWidth()/2-30,getHeight()/2-getWidth()/2+80,paint);
canvas.restore();
}
效果如图:
4.画出刻度
//刻度
for (int j=1;j<=60;j++){
canvas.save();
canvas.rotate(6*j,getWidth()/2,getHeight()/2);
paint.setStrokeWidth(2);
if (j%5==0){
paint.setStrokeWidth(4);
canvas.drawLine(getWidth()/2,getHeight()/2-getWidth()/2+5,getWidth()/2,getHeight()/2-getWidth()/2+30,paint);
}else {
paint.setStrokeWidth(2);
canvas.drawLine(getWidth()/2,getHeight()/2-getWidth()/2+5,getWidth()/2,getHeight()/2-getWidth()/2+20,paint);
}
canvas.restore();
}
效果如图:
5.获取系统时间,并且使指针动起来。
(1).在MyView类中,定义一个refresh方法,用invalidate方法刷新onDraw
//定义一个refresh方法,用invalidate方法刷新onDraw
public void refresh(int h,int m,int s){
this.hour=h;
this.minute=m;
this.second=s;
//刷新onDraw方法
invalidate();
}
(2).在Java文件中,绑定在布局文件中引用的MyView的id,用Calendar方法获取系统时间,引用refresh方法。
package com.example.weatherreport;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.example.weatherreport.customView.MyView;
public class ClockActivity extends AppCompatActivity {
private MyView myView;
private int hour;
private int minute;
private int second;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock);
myView=findViewById(R.id.clock_mv);
/**
* 获取系统时间
*/
Calendar calendar=Calendar.getInstance();
hour=calendar.get(Calendar.HOUR_OF_DAY);
minute=calendar.get(Calendar.MINUTE);
second=calendar.get(Calendar.SECOND);
myView.refresh(hour,minute,second);
}
}
(3).让指针动起来
new Thread(new Runnable() {
@Override
public void run() {
while (true){
second++;
if (second==60){
minute++;
second=0;
}
if (minute==60){
hour++;
minute=0;
}
Message message=handler.obtainMessage();
message.what=hour;
message.arg1=minute;
message.arg2=second;
handler.sendMessage(message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
用handler更新UI
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
myView.refresh(msg.what,msg.arg1,msg.arg2);
}
};
完整MyView代码如下:
package com.example.weatherreport.customView;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by lenovo on 2018/6/16.
*/
public class MyView extends View {
int hour=20;//时
int minute=20;//分
int second=0;//秒
public MyView(Context context) {
super(context);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画笔
Paint paint=new Paint();
//抗锯齿
paint.setAntiAlias(true);
//染色
paint.setColor(Color.GRAY);
//画圆(圆心横坐标,圆心纵坐标,半径,画笔);
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,paint);
//秒针
canvas.save();//保存当前画布
//设置指针的宽度
paint.setStrokeWidth(2);
//旋转角度(角度,起始X坐标,起始Y坐标)
canvas.rotate(second*6,getWidth()/2,getHeight()/2);
paint.setColor(Color.WHITE);
//画指针(起始位置X坐标,起始位置Y坐标,终止位置X坐标,终止位置Y坐标,画笔);
canvas.drawLine(getWidth()/2,getHeight()/2,getWidth()/2,getHeight()/2-getWidth()/2+100,paint);
canvas.restore();//恢复画布
//分针
canvas.save();//保存当前画布
//设置指针的宽度
paint.setStrokeWidth(5);
//旋转角度(角度,起始X坐标,起始Y坐标)
canvas.rotate(minute*6,getWidth()/2,getHeight()/2);
paint.setColor(Color.WHITE);
//画指针(起始位置X坐标,起始位置Y坐标,终止位置X坐标,终止位置Y坐标,画笔);
canvas.drawLine(getWidth()/2,getHeight()/2,getWidth()/2,getHeight()/2-getWidth()/2+200,paint);
canvas.restore();//恢复画布
//时针
canvas.save();//保存当前画布
//设置指针的宽度
paint.setStrokeWidth(8);
//旋转角度(角度,起始X坐标,起始Y坐标)
canvas.rotate(hour*30+minute*30/60,getWidth()/2,getHeight()/2);
paint.setColor(Color.WHITE);
//画指针(起始位置X坐标,起始位置Y坐标,终止位置X坐标,终止位置Y坐标,画笔);
canvas.drawLine(getWidth()/2,getHeight()/2,getWidth()/2,getHeight()/2-getWidth()/2+300,paint);
canvas.restore();//恢复画布
//时间
for (int i=1;i<=12;i++){
canvas.save();
//字体尺寸
paint.setTextSize(50);
canvas.rotate(30*i,getWidth()/2,getHeight()/2);
//画12个数字(文本内容,起始位置X坐标,起始位置Y坐标,画笔)
canvas.drawText(i+"",getWidth()/2-30,getHeight()/2-getWidth()/2+80,paint);
canvas.restore();
}
//刻度
for (int j=1;j<=60;j++){
canvas.save();
canvas.rotate(6*j,getWidth()/2,getHeight()/2);
paint.setStrokeWidth(2);
if (j%5==0){
paint.setStrokeWidth(4);
canvas.drawLine(getWidth()/2,getHeight()/2-getWidth()/2+5,getWidth()/2,getHeight()/2-getWidth()/2+30,paint);
}else {
paint.setStrokeWidth(2);
canvas.drawLine(getWidth()/2,getHeight()/2-getWidth()/2+5,getWidth()/2,getHeight()/2-getWidth()/2+20,paint);
}
canvas.restore();
}
}
//定义一个refresh方法,用invalidate方法刷新onDraw
public void refresh(int h,int m,int s){
this.hour=h;
this.minute=m;
this.second=s;
//刷新onDraw方法
invalidate();
}
}
完整Java代码如下:
package com.example.weatherreport;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.example.weatherreport.customView.MyView;
import java.util.Calendar;
public class ClockActivity extends AppCompatActivity {
private MyView myView;
private int hour;
private int minute;
private int second;
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
myView.refresh(msg.what,msg.arg1,msg.arg2);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock);
bindID();
/**
* 获取系统时间
*/
Calendar calendar=Calendar.getInstance();
hour=calendar.get(Calendar.HOUR_OF_DAY);
minute=calendar.get(Calendar.MINUTE);
second=calendar.get(Calendar.SECOND);
myView.refresh(hour,minute,second);
new Thread(new Runnable() {
@Override
public void run() {
while (true){
second++;
if (second==60){
minute++;
second=0;
}
if (minute==60){
hour++;
minute=0;
}
Message message=handler.obtainMessage();
message.what=hour;
message.arg1=minute;
message.arg2=second;
handler.sendMessage(message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
private void bindID() {
myView=findViewById(R.id.clock_mv);
}
}
怎么插入图片,代码如下:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.zhongbiaopan1);
RectF rectF = new RectF(getWidth() / 4 - getWidth() / 4, getHeight() / 2 - getWidth() / 2,getWidth() * 3 / 4 + getWidth() / 4, getHeight() / 2 + getWidth() / 2);
canvas.drawBitmap(bitmap, null, rectF, paint);
三.圆形ImageView(代码)
xml代码:
<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" >
<com.xc.xcskin.view.XCRoundImageView
android:id="@+id/roundImageView"
android:layout_centerInParent="true"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/roundimageview"
/>
</RelativeLayout>
自定义的圆形的ImageView类的实现代码如下:
package com.xc.xcskin.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* 自定义的圆形ImageView,可以直接当组件在布局中使用。
* @author caizhiming
*
*/
public class XCRoundImageView extends ImageView{
private Paint paint ;
public XCRoundImageView(Context context) {
this(context,null);
}
public XCRoundImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public XCRoundImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
}
/**
* 绘制圆形图片
* @author caizhiming
*/
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (null != drawable) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
Bitmap b = getCircleBitmap(bitmap, 14);
final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight());
final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
paint.reset();
canvas.drawBitmap(b, rectSrc, rectDest, paint);
} else {
super.onDraw(canvas);
}
}
/**
* 获取圆形图片方法
* @param bitmap
* @param pixels
* @return Bitmap
* @author caizhiming
*/
private Bitmap getCircleBitmap(Bitmap bitmap, int pixels) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
int x = bitmap.getWidth();
canvas.drawCircle(x / 2, x / 2, x / 2, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
}
上一篇: CSS3之新增选择器的详细介绍
下一篇: 鼠标拖动改变DIV的实例详解