系统学习android自定义View

自定义view绘制基础

添加链接描述

自定义绘制概述
  • 自定义绘制的方式是重写绘制方法,其中最常用的是 onDraw()
  • 绘制的关键是 Canvas 的使用
    Canvas 的绘制类方法: drawXXX() (关键参数:Paint)
    Canvas 的辅助类方法:范围裁切和几何变换
  • 可以使用不同的绘制方法来控制遮盖关系
自定义绘制四个级别

1.Canvas 的 drawXXX() 系列方法及 Paint 最常见的使用
2.Paint 的完全攻略
3.文字的绘制
4.Canvas 对绘制的辅助——范围裁切和几何变换。
5.使用不同的绘制方法来控制绘制顺序

学完上面得课程链接,我们来个实战运用。
模仿淘宝得banner轮播图效果
淘宝现在搞活动banner图下掉了,我们把最后实现得效果呈现上来
在这里插入图片描述

看图,四个角是需要圆角得,然后中间内容是banner轮播。

1.首先我们要画一个圆角矩形来实现这个圆角效果,但是圆角矩形填充没办法满足我们得需求。我们需要取矩形和圆角矩形不相交得部分,这里就要用到path和path的FillType。

我们来温习一下前面学习的知识点:
在这里插入图片描述

在这里插入图片描述
WINDING 非零环绕数原则
EVEN_ODD 奇偶原则
我们可以使用
如果你看到上面的三张图还是不能理解的画,建议看一下文章顶上的链接内容第一条

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们来看一下代码:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getMeasuredWidth();//得到测量的高度
        int height = getMeasuredHeight();//得到测量的宽度

        //保存画布
        canvas.save();

        //创建绘制矩形
        RectF rectF=new RectF(0,0,width,height);
        //绘制矩形,顺时针
        path1.addRect(rectF, Path.Direction.CW);
        //绘制圆角矩形,顺时针
        path1.addRoundRect(rectF,50,50, Path.Direction.CW);
        //设置填充模式,
        path1.setFillType(Path.FillType.EVEN_ODD);
		//设置填充颜色
        paint1.setColor(Color.RED);
        //在canvas上绘制填充对象
        canvas.drawPath(path1,paint1);
        //还原画布
        canvas.restore();

		//这个很重要,没次画完之后要重置以下path,paint不用重置。这里可以试一下
		//如果不添加这个的话,从后台返回前台的时候,绘制会有问题。有知道的小伙伴可以在评论区回复一下
        paint1.reset();
        path1.reset();
    }

最后这里还有一个非常重要的方法调用
避免性能优化,导致绘制不上去

 setWillNotDraw(false);

在这里插入图片描述
完整代码

public class RadiusLayout extends LinearLayout {
    public RadiusLayout(@NonNull Context context) {
        super(context);
        initView();
    }

    public RadiusLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();

    }

    public RadiusLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    public RadiusLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();

    }

    private void initView() {
        setWillNotDraw(false);
    }

    Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
    Path path1 = new Path();


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getMeasuredWidth();//得到测量的高度
        int height = getMeasuredHeight();//得到测量的宽度

        //保存画布
        canvas.save();

        //创建绘制矩形
        RectF rectF=new RectF(0,0,width,height);
        //绘制矩形,顺时针
        path1.addRect(rectF, Path.Direction.CW);
        //绘制圆角矩形,顺时针
        path1.addRoundRect(rectF,50,50, Path.Direction.CW);
        //设置填充模式,
        path1.setFillType(Path.FillType.EVEN_ODD);

        paint1.setColor(Color.RED);
        canvas.drawPath(path1,paint1);
        //还原画布
        canvas.restore();

        paint1.reset();
        path1.reset();
    }


}

public class RadiusLayout extends LinearLayout {
    public RadiusLayout(@NonNull Context context) {
        super(context);
        initView();
    }

    public RadiusLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();

    }

    public RadiusLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    public RadiusLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();

    }

    private void initView() {
        setWillNotDraw(false);
    }

    Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
    Path path1 = new Path();


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getMeasuredWidth();//得到测量的高度
        int height = getMeasuredHeight();//得到测量的宽度

        //保存画布
        canvas.save();

        //创建绘制矩形
        RectF rectF=new RectF(0,0,width,height);
        //绘制矩形,顺时针
        path1.addRect(rectF, Path.Direction.CW);
        //绘制圆角矩形,顺时针
        path1.addRoundRect(rectF,50,50, Path.Direction.CW);
        //设置填充模式,
        path1.setFillType(Path.FillType.EVEN_ODD);

        paint1.setColor(Color.RED);
        canvas.drawPath(path1,paint1);
        //还原画布
        canvas.restore();

        paint1.reset();
        path1.reset();
    }
    

}

这种方式需要我们把效果添加到顶层进行遮罩,那有没有更好的办法呢?
这里就要用到第五节课的内容了,绘制顺序

这里我们拿出关键的点给大家进行讲解,然后奉上源码
在这里插入图片描述
在这里插入图片描述
于是我们就有了下面的代码:

public class RadiusLayout extends LinearLayout {
    public RadiusLayout(@NonNull Context context) {
        super(context);
        initView();
    }

    public RadiusLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();

    }

    public RadiusLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    public RadiusLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();

    }

    private void initView() {
        setWillNotDraw(false);
    }

    Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
    Path path1 = new Path();


//    @Override
//    protected void onDraw(Canvas canvas) {
//        super.onDraw(canvas);
//
//    }


    @Override
    public void onDrawForeground(Canvas canvas) {
        super.onDrawForeground(canvas);
        int width = getMeasuredWidth();//得到测量的高度
        int height = getMeasuredHeight();//得到测量的宽度

        //保存画布
        canvas.save();

        //创建绘制矩形
        RectF rectF=new RectF(0,0,width,height);
        //绘制矩形,顺时针
        path1.addRect(rectF, Path.Direction.CW);
        //绘制圆角矩形,顺时针
        path1.addRoundRect(rectF,50,50, Path.Direction.CW);
        //设置填充模式,
        path1.setFillType(Path.FillType.EVEN_ODD);

        paint1.setColor(Color.RED);
        canvas.drawPath(path1,paint1);
        //还原画布
        canvas.restore();

        paint1.reset();
        path1.reset();
    }
}

我们把绘制这块的代码移到了onDrawForeground钩子函数中进行绘制

到这里基本上讲解完啦。
上面的两种方式,明现第二种能省掉一个view。所以效果也更加

<?xml version="1.0" encoding="utf-8"?>
<com.tudou.source.RadiusLayout 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="200dp"
    tools:context=".MainActivity">

    <com.stx.xhb.androidx.XBanner
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/xbanner"
        android:layout_width="match_parent"
        android:background="@color/colorPrimary"
        android:layout_height="match_parent"
        app:AutoPlayTime="3000"
        app:pointsContainerBackground="#44aaaaaa"
        app:pointsPosition="RIGHT"
        app:tipTextSize="12sp"
        app:isShowNumberIndicator="true"
        app:isShowIndicatorOnlyOne="true"
        app:pageChangeDuration="800"/>

</com.tudou.source.RadiusLayout>

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值