Android控件状态依赖

github地址:https://github.com/yhthu/ViewDependency

使用场景:

该Demo主要针对生产型Android客户端软件,界面存在多个输入和多个操作,且操作依赖于输入状态。

设定图中

  • 确认操作依赖于商品编码和储位的状态
  • 跳过操作不依赖于输入状态
  • 登记差异操作依赖于储位和数量的状态

输入框有三种状态:1)待输入;2)待校验;3)校验成功。操作需要当其依赖的输入数据校验成功,才能执行。
如果在Activity中去判断输入框状态,那么实际需要调用(3个输入框)
* (3种状态) * (3个按钮) = 27个 if
判断,对于状态的维护将使得整个程序可维护性极差,并随着输入和操作的增加,维护的状态呈指数增长。

使用方法:

由于目前未上传jcenter,仅供参考代码。

1. 布局文件引用WatchEditText和WatchButton

<com.android.yhthu.viewdependency.view.WatchEditText
    android:id="@+id/edit_query_1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:tag="editQuery1"
    android:imeOptions="actionNext"
    android:hint="商品编码"
    android:inputType="number"/>
<com.android.yhthu.viewdependency.view.WatchEditText
    android:id="@+id/edit_query_1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:tag="editQuery1"
    android:imeOptions="actionNext"
    android:hint="商品编码"
    android:inputType="number"/>

由于Library Module中的控件id不是常量(可参考ButterKnife对Library Module的支持采用R2的原因),这里采用了tag的方式。
2. 在Activity中通过注解申明依赖

@ViewName("商品编码")
private WatchEditText editQuery1;
@ViewName("储位")
private WatchEditText editQuery2;
@ViewName("数量")
private WatchEditText editQuery3;

@ViewDependency(name = @ViewName("确认"),         dependency = {"editQuery1", "editQuery2"})
private WatchButton buttonSearch1;
@ViewDependency(name = @ViewName("跳过")/*不依赖输入*/)
private WatchButton buttonSearch2;
@ViewDependency(name = @ViewName("登记缺货"),         dependency = {"editQuery2", "editQuery3"})
private WatchButton buttonSearch3;

ViewName定义控件名称,ViewDependency中dependency指定其依赖的控件tag。
3.
直接执行onClick和onEditorAction(修改状态)

@Override
public void onClick(View v) {
    if (v == buttonSearch1) {
        Toast.makeText(this, "调接口", Toast.LENGTH_SHORT).show();
    } else if (v == buttonSearch2) {
        Toast.makeText(this, "跳下一页", Toast.LENGTH_SHORT).show();
    } else if (v == buttonSearch3) {
        Toast.makeText(this, "登记缺货", Toast.LENGTH_SHORT).show();
    }
}

可以看出,这里并没有通过if判断各个输入控件的状态。

@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    if (actionId == EditorInfo.IME_ACTION_NEXT && v == editQuery1
            && (query1Str = editQuery1.getText().toString()).isEmpty()) {
        if (query1Str.equals("12345")) {
            editQuery1.complete();
            return true;
        }
    }
    // 省略代码
    return false;
}

onEditorAction模拟调用软件的Enter进行校验,这里需要注意通过editQuery1.complete()修改该EidtText的状态。

实现原理:

整个框架分为三个package:annotation、state和view。

  • 在annotation中定义ViewName和ViewDependency注解,分别用于WatchEditText和WatchButton。ViewName指定WatchEditText控件在业务中的名称,ViewDependency指定WatchButton依赖的WatchEditText控件;
/**
 * 控件状态依赖
 * Created by yanghao1 on 2016/12/19.
 */

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ViewDependency {

    /**
     * 控件名称(嵌套注解)
     *
     * @return
     */
    ViewName name() default @ViewName;

    /**
     * 控件状态依赖
     *
     * @return
     */
    String[] dependency() default {};
}
  • 在state中通过**状态模式**定义Enter、Verify、Complete,其基类为抽象类Operator,定义方法operator;
/**
 - 操作抽象接口
 - Created by yanghao1 on 2016/12/15.
 */
public abstract class Operator {

    // 操作对应的上下文
    protected Context context;

    /**
     * 操作
     *
     * @param operatorName 操作名称
     * @param viewName     控件名称
     * @return 是否可以执行操作
     */
    public abstract boolean operator(String operatorName, String viewName);
}
/**
 - 待输入状态(初始状态)
 - Created by yanghao1 on 2016/12/19.
 */
public class Enter extends Operator {

    private static Enter enter;

    private Enter(Context context) {
        this.context = context;
    }

    public static Enter getInstance(Context context) {
        if (enter == null) {
            enter = new Enter(context);
        }
        return enter;
    }

    @Override
    public boolean operator(String operatorName, String viewName) {
        Toast.makeText(context, String.format("[%s]为空,不允许执行[%s]", viewName, operatorName),
                Toast.LENGTH_SHORT).show();
        return false;
    }
}
  • WatchEditText和WatchButton定义控件的依赖关系。WatchEditText实现ViewState接口,其包含三种状态的转换方法。
/**
 * 控件状态
 * Created by yanghao1 on 2016/12/15.
 */
public interface ViewState {

    /**
     * 待输入状态(初始状态)
     */
    void enter();

    /**
     * 待校验状态(有输入(不为空),但未进行校验,或校验不成功)
     */
    void verify();

    /**
     * 有输入,并且校验成功
     */
    void complete();
}
时间: 2024-08-25 03:53:14

Android控件状态依赖的相关文章

Android程序 依赖库引用Gson 报java.lang.NoClassDefFoundError: com/google/gson/Gson 解决方法

Android 程序所依赖一个Library程序B , B 程序中用到格式化json串,转换成标准json串的要求 public static String jsonFormatter(String uglyJSONString) { Gson gson = new GsonBuilder().setPrettyPrinting().create(); JsonParser jp = new JsonParser(); JsonElement je = jp.parse(uglyJSONStri

Android Dagger依赖注入框架浅析

今天接触了Dagger这套android的依赖注入框架(DI框架),感觉跟Spring 的IOC差不多吧.这个框架它的好处是它没有采用反射技术(Spring是用反射的),而是用预编译技术,因为基于反射的DI非常地耗用资源(空间,时间) 由于现在开发都是用Android Studio了,所以我这里大概讲下配置Dagger框架的开发环境,需要怎么做. (由于Android Studio中用Gradle,所以跟传统我们用Eclipse配置的话,直接导入jar包,有点不一样.) 在开始看我的博文前,希望

Android项目依赖库管理方式简介

在实际的android项目开发过程中,我们一般都会用一些现有的第三方库来实现我们的需求,避免重复造轮子.普遍使用到的,例如:网络请求库.图片处理库.界面UI库(自定义View.动画效果等).各种第三方SDK库(聊天.推送等).笔者早期接触android使用eclipse开发时,当时对这些库的管理方式为:如果能jar包,则将jar包拷贝到libs目录下:还有一些源码库,则以library的方式倒入到工程中,调试. 修改.编译.发布.早期的这种库管理方式存在的一个严重问题是:无法自动跟踪版本.不能自

android studio依赖库工程Activity显示问题及库工程设置

android studio引用库工程其实不难,直接添加依赖module即可,但是我在操作过程中出现一些奇怪的问题,苦扰我一整天,为了祭奠这苦命的一天特别mark一下. 首先描述一下我的错误现象: studio配置完成后我就迫不及待的创建了一个项目,然后把以前用的库工程(eclipse工程)导入到studio中,然后创建一个项目引用一下看看效果咋样,以下分别描述两个项目遇到的问题: 出现问题: 1.调用库工程方法正常,但是在运行的时候提示我启动图标错误,原因是库工程和项目工程设置的启动图标指向同

android gradle 依赖项配置变更

在gradle-4.0之前的版本,引入依赖包时,都是按下面的做法 compile 'com.facebook.fresco:animated-gif:0.13.0' 但Android Studio 版本更新至3.0 的gradle-4.0版本中,包依赖配置语句做了修改,变成以下用法: implementation 'com.facebook.fresco:animated-gif:0.13.0' 或者 api 'com.facebook.fresco:animated-gif:0.13.0' 以

Android Gradle 依赖配置:implementation &amp; api

背景: Android Gradle plugin 3.0开始(对应Gradle版本 4.1及以上),原有的依赖配置类型compile已经被废弃,开始使用implementation.api和annotationProcessor类型分别替代.对应的,这三种替代配置类型针对具体的使用场景,具有不同的依赖行为.其中,implementation和api依赖又相对最为常用,对其具体含义也需要理解清,在实际项目中选择依赖配置时,也才能游刃有余. 首先看一下Android官方文档中关于依赖配置的详细介绍

Android不依赖Activity的全局悬浮窗实现

Android悬浮窗实现 实现基础 Android悬浮窗实现使用WindowManager ,WindowManager介绍 通过Context.getSystemService(Context.WINDOW_SERVICE)可以获得 WindowManager对象. 每一个WindowManager对象都和一个特定的 Display绑定. 想要获取一个不同的display的WindowManager,可以用 createDisplayContext(Display)来获取那个display的

Android快速开发必备——依赖注入(DI)类库的选择ButterKnife,AndroidAnnotations,RoboGuice

关注finddreams,一起学习,一起进步:http://blog.csdn.net/finddreams/article/details/45504133 现在做移动端开发的开发者,不管是Android和IOS,公司一般都是喜欢那种具备独立开发能力的人,因为APP项目相对较小,有时候一个人完全可以单独胜任一个项目.所以如果我们要能够具备独立开发的能力,快速敏捷开发是我们所必须要去思考的事情,毕竟一个人做APP所要做的事情还是挺多的,为了项目的如期上线,我们需要用到各种第三方的库和框架,这样可

Android开发进阶:Google依赖注入库Roboguice

Roboguice是一个用于Android应用的依赖注入框架,使用Google官方的Guice库位极大地简化了Android的依赖注入.让你的Android应用开发之路更加平坦顺利,编程更加简单有趣. 什么是依赖注入? 依赖注入是一种软件设计模式,无论是在运行时还是在编译时,允许删除.改变硬编码依赖性. 一些常用和普遍的依赖注入库有: Roboguice是一个用于Android应用的依赖注入框架,使用Google官方的Guice库位极大地简化了Android的依赖注入.让你的Android应用开