虽然现在开发Android界面DataBinding
和ViewBinding
已经普及开来,但是很多的老项目或者一些特殊的场合可能还会用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();
}
}