自定义InsetDrawable

 

一、概述

自定义InsetDrawable,扩展原生的InsetDrawable类功能。系统原生的InsetDrawable 是Drawable的子类,是用于嵌入一个子Drawable,且给该drawable设置inset属性,组成一个InsetDrawable对象。它可以实现设置的子Drawable与宿主控件区域有一定的间距。由属性 insetTop、insetLeft等体现。 

 InsetDrawable类
 
Drawable getDrawable();
void setDrawable(Drawable dr) 
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/home_quick"
    android:insetBottom="10dp"
    android:insetLeft="10dp"
    android:insetRight="10dp"
    android:insetTop="10dp" />

  

将一个控件设置背景为InsetDrawable, insetLeft、insetTop等均设置为10dp。由上图可以看出,InsetDrawable在设置inset属性后,会让其子Drawable对象显示区域与控件实际尺寸存在差距,显而易见,这个距离由inset属性值来决定,同时,被设置InsetDrawable对象的控件,变相的设置了Padding值,这个值也是写inset属性值相关。

二、需求: 

创建一个Drawable, 可以设置子Drawable, 同时可以设置Inset属性,但inset属性不能影响宿主控件的padding值,而且可以动态设置inset属性(系统的InsetDrawable是不能动态设置inset属性的,只能在xml中设置)。

三、实现自定义InsetDrawable

3.1 去除inset属性带来的padding效果

查看InsetDrawable源码

public class InsetDrawable extends DrawableWrapper    {


 @Override
    public boolean getPadding(Rect padding) {
        //子Drawable的padding值
        final boolean pad = super.getPadding(padding);
        getInsets(mTmpInsetRect);
        padding.left += mTmpInsetRect.left;
        padding.right += mTmpInsetRect.right;
        padding.top += mTmpInsetRect.top;
        padding.bottom += mTmpInsetRect.bottom;

        return pad || (mTmpInsetRect.left | mTmpInsetRect.right
                | mTmpInsetRect.top | mTmpInsetRect.bottom) != 0;
    }

    //将原有的padding值进行修改,增加inset属性影响
    private void getInsets(Rect out) {
        final Rect b = getBounds();
        out.left = mState.mInsetLeft.getDimension(b.width());
        out.right = mState.mInsetRight.getDimension(b.width());
        out.top = mState.mInsetTop.getDimension(b.height());
        out.bottom = mState.mInsetBottom.getDimension(b.height());
    }
。。。。
}

public abstract class DrawableWrapper extends Drawable implements Drawable.Callback {

    @Override
    public boolean getPadding(@NonNull Rect padding) {
        return mDrawable != null && mDrawable.getPadding(padding);
    }

。。。。
}

如上源码可以看出,是将原padding值增加inset属性影响

要去除padding效果,重写getPadding方法如下

    @Override
    public boolean getPadding(Rect padding) {
//        return super.getPadding(padding);
        return mDrawable != null && mDrawable.getPadding(padding);
    }

只用管Drawable设置padding的逻辑。

3.2 动态设置Inset属性

由于InsetState 等状态类都是final修改且不对外公共使用的类,它无法继承和重写,InsetDrawble也未提供相应的api可以修改inset属性值。但从源中可以看出,inset属性生效的逻辑是在onBoundsChange(Rect recf) 方法内实现的。源码如下:

    @Override
    protected void onBoundsChange(Rect bounds) {
        final Rect r = mTmpRect;
        r.set(bounds);
        //将原有的bounds区域增加inset属性影响
        r.left += mState.mInsetLeft.getDimension(bounds.width());
        r.top += mState.mInsetTop.getDimension(bounds.height());
        r.right -= mState.mInsetRight.getDimension(bounds.width());
        r.bottom -= mState.mInsetBottom.getDimension(bounds.height());

        // Apply inset bounds to the wrapped drawable.
        super.onBoundsChange(r);
    }

 自定义InsetDrawable代码如下:

package com.app.zxjt.widget.widget;

import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;

import androidx.annotation.Nullable;

/**
 * Created by liuyu
 * on 2021/9/13
 */
public class CustomInsetDrawable extends InsetDrawable {

    private Drawable mDrawable;
    private CustomInsets mInsets = new CustomInsets();

    public CustomInsetDrawable(@Nullable Drawable drawable) {
        super(drawable, 0);
        mDrawable = drawable;
    }

    @Override
    public boolean getPadding(Rect padding) {
        //return super.getPadding(padding);
        return mDrawable != null && mDrawable.getPadding(padding);
    }

    @Override
    protected void onBoundsChange(Rect r) {
        resetBounds(r);
        super.onBoundsChange(r);
    }

    private void resetBounds(Rect r) {
        if (r != null) {
            r.left += mInsets.left;
            r.top += mInsets.top;
            r.bottom -= mInsets.bottom;
            r.right -= mInsets.right;
        }
    }

    @Override
    public void setDrawable(Drawable drawable) {
        super.setDrawable(drawable);
        mDrawable = drawable;
    }

    @Nullable
    @Override
    public Drawable getDrawable() {
       return super.getDrawable();
    }

    public void setInsets(int insetLeft, int insetTop, int insetRight, int insetBottom) {
        notifyInsets(insetLeft, insetTop, insetRight, insetBottom);
    }

    public void setInsets(int insets) {
        notifyInsets(insets, insets, insets, insets);
    }

    public void setInsetLeft(int insetLeft) {
        if (mInsets.left != insetLeft) {
            mInsets.left = insetLeft;
            notifyBounds();
        }
    }

    public void setInsetTop(int insetTop) {
        if (mInsets.top != insetTop) {
            mInsets.top = insetTop;
            notifyBounds();
        }
    }

    public void setInsetRight(int insetRight) {
        if (mInsets.right != insetRight) {
            mInsets.right = insetRight;
            notifyBounds();
        }
    }

    public void setInsetBottom(int insetBottom) {
        if (mInsets.bottom != insetBottom) {
            mInsets.bottom = insetBottom;
            notifyBounds();
        }
    }

    private void notifyBounds() {
        onBoundsChange(getBounds());
        invalidateSelf();
    }

    private void notifyInsets(int insetLeft, int insetTop, int insetRight, int insetBottom) {
        if (mInsets.left != insetLeft || mInsets.top != insetTop || mInsets.right != insetRight || mInsets.bottom != insetBottom) {
            mInsets.left = insetLeft;
            mInsets.top = insetTop;
            mInsets.right = insetRight;
            mInsets.bottom = insetBottom;
            notifyBounds();
        }
    }

    public CustomInsets getInsets() {
        return mInsets;
    }

    public static class CustomInsets {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }
}


上述自定义的Drawable就可以满足需求了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值