欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义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" />

效果如图:

自定义View

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();
        }

效果如图:

自定义View

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();
        }

效果如图:

自定义View

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;  


    }  
}