我正在参加创作者训练营第5期,点击了解活动概况
👨🎓作者简介:一位喜欢写作,计科专业大二菜鸟
🏡个人主页:starry陆离
🕒首发日期:2022年8月3日星期三
🌌上期文章:『Android根底入门』dataBinding的简略使用
📚订阅专栏:『Android根底入门』
假如文章有帮到你的话记得点赞👍+收藏💗支撑一下哦
『Android根底入门』自定义view控件画一个五彩斑斓的黑圈圈
1.前言
今天咱们来完成一个好玩的小功用,自定义一个view控件在随机方位画一个随机色彩的圆圈,并完成点击事情监听移除与清空功用
首要来康康作用吧
2.xml布局规划
首要咱们创立一个空项目,简略的来完成这个xml文件布局
布局主要分为两个部分,上大半部分是咱们用来画图的view布局,咱们的图画最终会烘托到这个部分。
下半部分是一个嵌套的束缚布局,布局中放置三个button,分别来完成在view布局中增加一个圆,移除一个圆以及清空所有的圆
activity_main.xml源代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<View
android:id="@+id/view"
android:background="@color/black"
android:layout_width="match_parent"
android:layout_height="500dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/view">
<Button
android:id="@+id/moveBtn"
android:layout_width="300dp"
android:layout_height="60dp"
android:text="move"
app:layout_constraintBottom_toTopOf="@+id/clearBtn"
app:layout_constraintStart_toStartOf="@+id/addBtn"
app:layout_constraintTop_toBottomOf="@+id/addBtn" />
<Button
android:id="@+id/addBtn"
android:layout_width="300dp"
android:layout_height="60dp"
android:text="add"
app:layout_constraintBottom_toTopOf="@+id/moveBtn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/clearBtn"
android:layout_width="300dp"
android:layout_height="60dp"
android:text="clear"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/moveBtn"
app:layout_constraintTop_toBottomOf="@+id/moveBtn" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
3.Activity点击事情
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.addBtn).setOnClickListener(this);
findViewById(R.id.moveBtn).setOnClickListener(this);
findViewById(R.id.clearBtn).setOnClickListener(this);
}
@Override
public void onClick(View view) {
if(view.getId()==R.id.addBtn){
Toast.makeText(MainActivity.this,"add",Toast.LENGTH_SHORT).show();
}else if(view.getId()==R.id.clearBtn){
Toast.makeText(MainActivity.this,"clear",Toast.LENGTH_SHORT).show();
}else if(view.getId()==R.id.moveBtn){
Toast.makeText(MainActivity.this,"Move",Toast.LENGTH_SHORT).show();
}
}
}
4.自定义view画布
咱们需求自定义一个画布类
用自定义的CircleView继承View父类替换View控件
View类中有onDraw()
办法,咱们经过重写此办法完成在view布局上作画
有了画布天然要有画布,创立一支红色的画笔,调用画圆的办法drawCircle()
//有了画布canvas,咱们还需求一支画笔
Paint paint=new Paint();
paint.setColor(Color.RED);
public class CircleView extends View {
public CircleView(Context context) {
super(context);
}
public CircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
//设置画布的背景色为黑色
this.setBackgroundColor(Color.BLACK);
//有了画布canvas,咱们还需求一支画笔
Paint paint=new Paint();
paint.setColor(Color.RED);
//用画笔paint画一个圆心坐标为(400,500)的半径为100的圆
canvas.drawCircle(400,500,100,paint);
}
}
为什么运行加载,画布上就出现了一个红色的圆呢?由于在加载CircleView的时分会自动履行onDraw()
办法且默认只履行一次;
为了不让一运行就出现圆,而是经过咱们的点击事情出现圆,咱们定义一个布尔值变量,在MainActivity中经过按钮的点击事情增加圆
5.完成画多个圆
画多个圆就需求将圆保存在一个列表List或者是数组中,然后再到onDraw()
办法中依次烘托这些圆到view布局上
除此之外,咱们生成的圆目标的色彩和方位应该是随机的,并且圆的方位不应该超出画布的规模
因而咱们创立多个类,分别来完成这些功用
5.1圆目标
static class Circle{
float x,y;
final float RADIUS=120;
final int color;
public Circle(float x, float y,int color) {
this.x = x;
this.y = y;
this.color=color;
}
}
5.2随机色彩
Color.argb(200,r,g,b)
是回来是一个代表色彩的整数值,argb()
里的四个参数就是a(透明度),r,g,b(红,绿,蓝三原色)的值
public static int getRandomColor(){
Random random=new Random();
int r=random.nextInt(256);
int g=random.nextInt(256);
int b=random.nextInt(256);
return Color.argb(200,r,g,b);
}
5.3随机方位增加一个圆
/*
* 增加一个圆
* */
public void addCircle(){
//在view的宽高规模内,随机生成一个坐标
float x=(float) (Math.random()*viewWidth);
float y=(float) (Math.random()*viewHeight);
//束缚条件,不让圆超出画布规模
//宽度束缚
if(x<120f){
x=120f;
}else if(x>viewWidth-120f){
x=viewWidth-120f;
}
//高度束缚
if(y<120f){
y=120f;
}else if(y>viewHeight-120f){
y=viewHeight-120f;
}
//将圆增加到列表中
CircleView.Circle circle=new CircleView.Circle(x,y,CircleView.getRandomColor());
CircleView.circleList.add(circle);
}
5.4移除与清空
public void removeCircle(){
if(!circleList.isEmpty()){
circleList.remove(circleList.size()-1);
}
}
public void clearCircle(){
circleList.clear();
}
5.5在Activity中监听点击事情
留意最后一行代码:在子线程中从头履行一次 circleView.postInvalidate();
由于咱们之前说过自定义的的CircleView类中的onDraw()
办法在加载这个控件时只会履行一次,而咱们每一次点击都要重写烘托view,所以需求在每一次用户点击操作后在子线程中从头烘托view控件,这样才能让用户看到实时的作用
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private CircleView circleView;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.addBtn).setOnClickListener(this);
findViewById(R.id.moveBtn).setOnClickListener(this);
findViewById(R.id.clearBtn).setOnClickListener(this);
circleView=findViewById(R.id.view);
}
@Override
public void onClick(View view) {
if(view.getId()==R.id.addBtn){
Toast.makeText(MainActivity.this,"add",Toast.LENGTH_SHORT).show();
circleView.addCircle();
}else if(view.getId()==R.id.clearBtn){
Toast.makeText(MainActivity.this,"clear",Toast.LENGTH_SHORT).show();
circleView.clearCircle();
}else if(view.getId()==R.id.moveBtn){
Toast.makeText(MainActivity.this,"Move",Toast.LENGTH_SHORT).show();
circleView.removeCircle();
}
//在子线程中从头履行一次
circleView.postInvalidate();
}
}
6.作用展示
7.完好代码
7.1MainActivity
package com.hnucm.ad0301;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private CircleView circleView;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.addBtn).setOnClickListener(this);
findViewById(R.id.moveBtn).setOnClickListener(this);
findViewById(R.id.clearBtn).setOnClickListener(this);
circleView=findViewById(R.id.view);
}
@Override
public void onClick(View view) {
if(view.getId()==R.id.addBtn){
Toast.makeText(MainActivity.this,"add",Toast.LENGTH_SHORT).show();
circleView.addCircle();
}else if(view.getId()==R.id.clearBtn){
Toast.makeText(MainActivity.this,"clear",Toast.LENGTH_SHORT).show();
circleView.clearCircle();
}else if(view.getId()==R.id.moveBtn){
Toast.makeText(MainActivity.this,"Move",Toast.LENGTH_SHORT).show();
circleView.removeCircle();
}
//在子线程中从头履行一次
circleView.postInvalidate();
}
}
7.2CircleView
package com.hnucm.ad0301;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class CircleView extends View {
public static List<Circle>circleList=new ArrayList<>();
public float viewWidth;
public float viewHeight;
public CircleView(Context context) {
super(context);
}
public CircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
//获取画布的宽高
viewWidth=canvas.getWidth();
viewHeight=canvas.getHeight();
//设置画布的背景色为黑色
this.setBackgroundColor(Color.BLACK);
//有了画布canvas,咱们还需求一支画笔
Paint paint=new Paint();
//遍历列表画圆
for(int i=0;i<circleList.size();++i){
Circle circle=circleList.get(i);
paint.setColor(circle.color);
canvas.drawCircle(circle.x,circle.y,circle.RADIUS,paint);
}
}
/*
* 增加一个圆
* */
public void addCircle(){
//在view的宽高规模内,随机生成一个坐标
float x=(float) (Math.random()*viewWidth);
float y=(float) (Math.random()*viewHeight);
//束缚条件,不让圆超出画布规模
//宽度束缚
if(x<120f){
x=120f;
}else if(x>viewWidth-120f){
x=viewWidth-120f;
}
//高度束缚
if(y<120f){
y=120f;
}else if(y>viewHeight-120f){
y=viewHeight-120f;
}
//将圆增加到列表中
CircleView.Circle circle=new CircleView.Circle(x,y,CircleView.getRandomColor());
CircleView.circleList.add(circle);
}
public void removeCircle(){
if(!circleList.isEmpty()){
circleList.remove(circleList.size()-1);
}
}
public void clearCircle(){
circleList.clear();
}
static class Circle{
float x,y;
final float RADIUS=120;
final int color;
public Circle(float x, float y,int color) {
this.x = x;
this.y = y;
this.color=color;
}
}
public static int getRandomColor(){
Random random=new Random();
int r=random.nextInt(256);
int g=random.nextInt(256);
int b=random.nextInt(256);
return Color.argb(200,r,g,b);
}
}
7.3activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<com.hnucm.ad0301.CircleView
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="500dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/view">
<Button
android:id="@+id/moveBtn"
android:layout_width="301dp"
android:layout_height="59dp"
android:text="move"
app:layout_constraintBottom_toTopOf="@+id/clearBtn"
app:layout_constraintStart_toStartOf="@+id/addBtn"
app:layout_constraintTop_toBottomOf="@+id/addBtn" />
<Button
android:id="@+id/addBtn"
android:layout_width="300dp"
android:layout_height="60dp"
android:text="add"
app:layout_constraintBottom_toTopOf="@+id/moveBtn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/clearBtn"
android:layout_width="300dp"
android:layout_height="60dp"
android:text="clear"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/moveBtn"
app:layout_constraintTop_toBottomOf="@+id/moveBtn" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>