ViewOptional:一个安全便利的查找View的工具

虽然现在开发Android界面DataBindingViewBinding已经普及开来,但是很多的老项目或者一些特殊的场合可能还会用findViewById这种最原始的写法,但这种写法比较麻烦,又不太安全,本文就分享一个简单的用于安全、便利的获取View的工具–ViewOptional

1. 使用示例

View root = null;
//获取对应View,再进行对应操作
ViewOptional<View> vo1 = ViewOptional.find(root, R.id.tvName);
View view1 = vo1.get();
boolean isEmpty = vo1.isEmpty();
boolean isPresent = vo1.isPresent();
boolean isTextView = vo1.isInstanceOf(TextView.class);
vo1.ifPresent((View view) -> {
    //doSomething
});
vo1.ifInstanceOf(TextView.class, (TextView tvName) -> {
    //doSomething
});

//利用方法链直接操作
ViewOptional.find(root, R.id.tvName).ifPresent(view -> {
    //doSomething
});

//构造时提供类型参数,来自动转换类型
ViewOptional.find((root, R.id.tvName, TextView.class)
        .ifPresent((TextView tvName) -> {
            //doSomething
        });

//提供备选id,如果第一个找不到对应View,就依次尝试备选的
ViewOptional.find(root, TextView.class, R.id.tvName, R.id.tvUserName, R.id.tvAccountName)
        .ifPresent((TextView tvName) -> {
            //doSomething
        });

2. 接口说明

  • 静态工厂方法 <T extends View> ViewOptional<T> find(@Nullable View rootView, @IdRes int id):从一个控件rootView中查找指定id的View,来构造对应ViewOptional

  • 静态工厂方法 <T extends View> ViewOptional<T> find(@Nullable View rootView, @IdRes int id, Class<T> tClass):从一个控件rootView中查找指定id的View,尝试转换为指定类型,来构造对应ViewOptional

  • 静态工厂方法 <T extends View> ViewOptional<T> find(@Nullable View rootView, Class<T> tClass, @IdRes int id, int... defIds):从一个控件rootView中查找指定id的View,尝试转换为指定类型,来构造对应ViewOptional,如果第一个id没有对应的View就依次尝试后面的id;

  • 静态工厂方法 <T extends View> ViewOptional<T> of(@Nullable T view):从已有的变量来构建ViewOptional

  • 方法V get():获取对应的View,如果不存在,抛出异常;

  • 方法boolean isEmpty:判断当前ViewOptional是否为空;

  • 方法boolean isPresent():判断当前ViewOptional是否有值;

  • 方法<AV extends View> boolean isInstanceOf(Class<AV> vcClass):判断当前的View是否为指定类型;

  • 方法void ifPresent(Consumer<? super V> consumer):如果有值,则执行对应consumer;

  • 方法void ifPresent(Consumer<? super V> consumer, Runnable elseRunnable):如果有值,则执行对应consumer,否则,就执行elseRunnable

  • 方法<AV extends View> void ifInstanceOf(Class<AV> avClass, Consumer<? super AV> consumer):如果控件是指定类型,则执行对应consumer;

  • 方法<AV extends View> void ifInstanceOf(Class<AV> avClass, Consumer<? super AV> consumer, Runnable elseRunnable):如果控件是指定类型,则执行对应consumer,否则,就执行elseRunnable

  • 方法V orElse(V other):如果有值,就返回对应View,否则,返回默认值other

  • 方法V orElseGet(Supplier<? extends V> other):如果有值,就返回对应View,否则,只用Supplier返回的默认值;

3. 完整实现

public class ViewOptional<V extends View> {
    private V view;

    private ViewOptional() {
    }

    private ViewOptional(V view) {
        this.view = view;
    }

    public static <T extends View> ViewOptional<T> find(@Nullable View rootView, @IdRes int id, Class<T> tClass) {
        if (rootView == null) {
            return of(null);
        } else {
            View view = rootView.findViewById(id);
            if (tClass.isInstance(view)) {
                return of(tClass.cast(view));
            } else {
                return of(null);
            }
        }
    }

    public static <T extends View> ViewOptional<T> find(@Nullable View rootView, @IdRes int id) {
        if (rootView == null) {
            return of(null);
        } else {
            return of(rootView.findViewById(id));
        }
    }

    public static <T extends View> ViewOptional<T> find(@Nullable View rootView, Class<T> tClass, @IdRes int id, int... defIds) {
        if (rootView == null) {
            return of(null);
        } else {
            View view = rootView.findViewById(id);
            if (tClass.isInstance(view)) {
                return of(tClass.cast(view));
            } else if (defIds != null) {
                for (int defId : defIds) {
                    view = rootView.findViewById(defId);
                    if (tClass.isInstance(view)) {
                        return of(tClass.cast(view));
                    }
                }
                return of(null);
            } else {
                return of(null);
            }
        }
    }

    public static <T extends View> ViewOptional<T> of(@Nullable T view) {
        return new ViewOptional<>(view);
    }

    public V get() {
        if (view == null) {
            throw new NoSuchElementException("No value present");
        }
        return view;
    }

    public boolean isEmpty() {
        return view == null;
    }

    public boolean isPresent() {
        return view != null;
    }

    public <AV extends View> boolean isInstanceOf(Class<AV> vcClass) {
        return vcClass.isInstance(view);
    }

    public void ifPresent(Consumer<? super V> consumer) {
        if (view != null)
            consumer.accept(view);
    }

    public void ifPresent(Consumer<? super V> consumer, Runnable elseRunnable) {
        if (view != null)
            consumer.accept(view);
        else
            elseRunnable.run();
    }

    public <AV extends View> void ifInstanceOf(Class<AV> avClass, Consumer<? super AV> consumer) {
        if (isInstanceOf(avClass)) {
            consumer.accept(avClass.cast(view));
        }
    }

    public <AV extends View> void ifInstanceOf(Class<AV> avClass, Consumer<? super AV> consumer, Runnable elseRunnable) {
        if (isInstanceOf(avClass)) {
            consumer.accept(avClass.cast(view));
        } else {
            elseRunnable.run();
        }
    }

    public V orElse(V other) {
        return view != null ? view : other;
    }

    public V orElseGet(Supplier<? extends V> other) {
        return view != null ? view : other.get();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值