IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 自定义InsetDrawable -> 正文阅读

[移动开发]自定义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就可以满足需求了。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-14 13:28:08  更:2021-09-14 13:29:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:02:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码