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
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>
效果图:
文章来源: 自定义View