一.自定义View分类
View下面有
ImageView
ImageButton
QuickContactBadge
AppCompatImageViewTextView
EditText
Button
RadioButton
ToggleButton
CheckBox
Switch
TextClock
Chronometer
RowHeaderView- ViewGruop
LinearLayout
ReativeLayout
ViewPager
AbsoiuteLayout
FrameLayout
GridLayout - TextureView
- ViewStub
- TabLtem
- Spce
二.时钟案例
一.新建一个类继承View
package com.example.myapplication.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
import com.example.myapplication.R;
/**
* Created by lyj on 2018/6/15.
*/
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);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
二.在onDraw方法里面定义画笔,画东西
Paint paint = new Paint();
设置颜色
paint.setColor(Color.RED);
抗锯齿
paint.setAntiAlias(true);
画一个圆,把表盘背景图设置进去
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.watch);
RectF rectF = new RectF(getWidth() / 4+25, getHeight() / 2 - getWidth() / 4+25, getWidth() / 4 * 3-25, getHeight() / 2 + getHeight() / 8);
canvas.drawBitmap(bitmap, null, rectF, paint);
画时针
canvas.save();
canvas.rotate(hours * 30 + minute * 30 / 60, getWidth() / 2, getHeight() / 2);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(5);
canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2 - getHeight() / 8 + 55, paint);
canvas.restore();
画分针
canvas.save();
canvas.rotate(minute * 6, getWidth() / 2, getHeight() / 2);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(3);
canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2 + 12, getHeight() / 2 - getHeight() / 8 + 40, paint);
canvas.restore();
画秒针
canvas.save();
canvas.rotate(second * 6, getWidth() / 2, getHeight() / 2);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(1);
canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2 + 15, getHeight() / 2 - getHeight() / 8 + 20, paint);
canvas.restore();
画刻度
for (int i = 0; i <= 60; i++) {
canvas.save();
canvas.rotate(6 * i, getWidth() / 2, getHeight() / 2);
paint.setStrokeWidth(2);
if (i % 5 == 0) {
paint.setStrokeWidth(8);
canvas.drawLine(getWidth() / 2, getHeight() / 2 - getHeight() / 8 + 20, getWidth() / 2, getHeight() / 2 - getWidth() / 4 + 35, paint);
} else {
paint.setStrokeWidth(4);
canvas.drawLine(getWidth() / 2, getHeight() / 2 - getHeight() / 8 + 20, getWidth() / 2, getHeight() / 2 - getWidth() / 4+40, paint);
}
canvas.restore();
}
每画完一个图形都需要canvas.save();
保存一下
三.实现指针动起来
重新写一个方法
public void refresh(int h, int m, int s) {
this.hours = h;
this.minute = m;
this.second = s;
invalidate();//再次触发onDraw方法
}
这是新建的类的完整代码
package com.example.myapplication.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
import com.example.myapplication.R;
/**
* Created by lyj on 2018/6/15.
*/
public class MyView extends View {
private int hours = 20;
private int minute = 20;
private 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.setColor(Color.RED);
//抗锯齿
paint.setAntiAlias(true);
/*
前两个参数:圆心的位置
第三参数:半径
*/
//canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/4,paint);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.watch);
RectF rectF = new RectF(getWidth() / 4+25, getHeight() / 2 - getWidth() / 4+25, getWidth() / 4 * 3-25, getHeight() / 2 + getHeight() / 8);
canvas.drawBitmap(bitmap, null, rectF, paint);
//画直线(时针)
canvas.save();
canvas.rotate(hours * 30 + minute * 30 / 60, getWidth() / 2, getHeight() / 2);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(5);
canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2 - getHeight() / 8 + 55, paint);
canvas.restore();
//画直线(分针)
canvas.save();
canvas.rotate(minute * 6, getWidth() / 2, getHeight() / 2);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(3);
canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2 + 12, getHeight() / 2 - getHeight() / 8 + 40, paint);
canvas.restore();
//画直线(秒针)
canvas.save();
canvas.rotate(second * 6, getWidth() / 2, getHeight() / 2);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(1);
canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2 + 15, getHeight() / 2 - getHeight() / 8 + 20, paint);
canvas.restore();
for (int i = 0; i <= 60; i++) {
canvas.save();
canvas.rotate(6 * i, getWidth() / 2, getHeight() / 2);
paint.setStrokeWidth(2);
if (i % 5 == 0) {
paint.setStrokeWidth(8);
canvas.drawLine(getWidth() / 2, getHeight() / 2 - getHeight() / 8 + 20, getWidth() / 2, getHeight() / 2 - getWidth() / 4 + 35, paint);
} else {
paint.setStrokeWidth(4);
canvas.drawLine(getWidth() / 2, getHeight() / 2 - getHeight() / 8 + 20, getWidth() / 2, getHeight() / 2 - getWidth() / 4+40, paint);
}
canvas.restore();
}
}
public void refresh(int h, int m, int s) {
this.hours = h;
this.minute = m;
this.second = s;
invalidate();//再次触发onDraw方法
}
}
activity类
得到当前时间
Calendar calendar = Calendar.getInstance();
hours = calendar.get(Calendar.HOUR_OF_DAY);
minute = calendar.get(Calendar.MINUTE);
second = calendar.get(Calendar.SECOND);
主线程不能做耗时操作,所以开启一个线程让指针动起来
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
second++;
if (second == 60) {
second = 0;
minute++;
}
try {
Message message = handler.obtainMessage();
message.what = hours;
message.arg1 = minute;
message.arg2 = second;
handler.sendMessage(message);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
activity类的完整代码
package com.example.myapplication.view;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.example.myapplication.R;
import java.util.Calendar;
public class MyViewActivity extends AppCompatActivity {
private MyView myView;
private int hours;
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_my_view);
myView = findViewById(R.id.my_view);
Calendar calendar = Calendar.getInstance();
hours = calendar.get(Calendar.HOUR_OF_DAY);
minute = calendar.get(Calendar.MINUTE);
second = calendar.get(Calendar.SECOND);
myView.refresh(hours, minute, second);
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
second++;
if (second == 60) {
second = 0;
minute++;
}
try {
Message message = handler.obtainMessage();
message.what = hours;
message.arg1 = minute;
message.arg2 = second;
handler.sendMessage(message);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
布局文件需要引入自己的控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.myapplication.view.MyViewActivity">
<com.example.myapplication.view.MyView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/my_view"/>
</LinearLayout>
效果图:
三.圆形ImageView
新建一个类继承ImageView
package com.example.myapplication.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Created by lyj on 2018/6/15.
*/
@SuppressLint("AppCompatCustomView")
public class MyImageView extends ImageView{
private Paint mPaint; //画笔
private int mRadius; //圆形图片的半径
private float mScale; //图片的缩放比例
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = size / 2;
setMeasuredDimension(size, size);
}
@Override
protected void onDraw(Canvas canvas) {
mPaint = new Paint();
Bitmap bitmap = drawableToBitmap(getDrawable());
//初始化BitmapShader,传入bitmap对象
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//计算缩放比例
mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
bitmapShader.setLocalMatrix(matrix);
mPaint.setShader(bitmapShader);
//画圆形,指定好中心点坐标、半径、画笔
canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
}
//写一个drawble转BitMap的方法
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}
}
布局文件引入自定义图片控件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.myapplication.view.MyImageActivity">
<com.example.myapplication.view.MyImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/a"
android:id="@+id/img_myView"/>
</LinearLayout>
效果图: