Android 自定义控件的双向绑定(DataBinding)和EditText的内部滚动

一个关于类似TextInputLayout的功能的自定义控件进行双向绑定
用法:
什么是BindingAdapter?
BindingAdapter用来设置布局中View的自定义属性,当使用该属性时,可以自定义其行为。
1、作用于方法
2、它定义了xml的属性赋值的java实现
3、方法必须为公共静(public static)方法,可以有一到多个参数。

  @BindingAdapter("app:text")
    public static void setText(TitleWithHintTextInputLayout customTextInputLayout, String text) {
        customTextInputLayout.setText(text);
    }

什么是InverseBindingAdapter?
InverseBindingAdapter用于关联某个用于接收View变更的方法,典型的例子EditText.TextWatcher接收输入字符的变更。这与BindingAdapters有一定的相似性:

   @InverseBindingAdapter(attribute = "app:text", event = "app:textAttrChanged")
    public static String getText(CustomTextInputLayout customTextInputLayout) {
        return customTextInputLayout.getText();
    }

事件的默认值是带有AttrChanged的属性名称。在上面的例子中,默认值是android:textAttrChanged,即使它没有提供。

事件属性用于通知数据绑定系统值已更改。开发人员通常会创建一个BindingAdapter来分配事件。比如:

  @BindingAdapter(value = "app:textAttrChanged", requireAll = false)
    public static void setListener(CustomTextInputLayout customTextInputLayout, final InverseBindingListener listener) {
        if (listener != null) {
            SimpleTextWatcher newTextWatch = new SimpleTextWatcher() {
                @Override
                public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
                    listener.onChange();
                }
            };
            SimpleTextWatcher oldTextWatch = ListenerUtil.trackListener(customTextInputLayout, newTextWatch, R.id.textWatcher);
            if (oldTextWatch != null) {
                customTextInputLayout.removeTextWatch(oldTextWatch);
            }
            customTextInputLayout.addTextWatch(newTextWatch);
        }
    }

完整代码:

public class CustomTextInputLayout extends RelativeLayout {
    private AppCompatTextView tvHint;
    private MultipleLinesEditText editText;

    public CustomTextInputLayout(Context context) {
        this(context, null);
    }

    public CustomTextInputLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs);
    }

    private void initView(Context context, AttributeSet attributeSet) {
        LayoutInflater.from(context).inflate(R.layout.custom_text_input_layout, this, true);
        tvHint = findViewById(R.id.tv_hint);
        editText = findViewById(R.id.et_content);
        TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.CustomTextInputLayout);
        String title = typedArray.getString(R.styleable.CustomTextInputLayout_title);
        String hint = typedArray.getString(R.styleable.CustomTextInputLayout_hint);
        String text = typedArray.getString(R.styleable.CustomTextInputLayout_text);
        int maxLines = typedArray.getIndex(R.styleable.CustomTextInputLayout_maxLines);
        editText.setMaxLines(maxLines);
        if (!TextUtils.isEmpty(hint)) {
            setHint(hint);
        }
        if (!TextUtils.isEmpty(title)) {
            setTitle(title);
        }
        if (!TextUtils.isEmpty(text)) {
            setText(text);
        }
        typedArray.recycle();
    }

    public void setHint(String hint) {
        editText.setHint(hint);
    }

    public void setTitle(String text) {
        tvHint.setText(text);
    }

    public void setText(String text) {
        if (!getText().equals(text)) {
            editText.setText(text);
        }

    }

    private String getText() {
        Editable text = editText.getText();
        if (text != null) {
            return text.toString();
        } else {
            return "";
        }

    }

    private void addTextWatch(TextWatcher textWatcher) {
        editText.addTextChangedListener(textWatcher);
    }

    private void removeTextWatch(TextWatcher textWatcher) {
        editText.removeTextChangedListener(textWatcher);
    }

    @BindingAdapter("app:text")
    public static void setText(CustomTextInputLayout customTextInputLayout, String text) {
        customTextInputLayout.setText(text);
    }

    @InverseBindingAdapter(attribute = "app:text", event = "app:textAttrChanged")
    public static String getText(CustomTextInputLayout customTextInputLayout) {
        return customTextInputLayout.getText();
    }

    @BindingAdapter(value = "app:textAttrChanged", requireAll = false)
    public static void setListener(CustomTextInputLayout customTextInputLayout, final InverseBindingListener listener) {
        if (listener != null) {
            SimpleTextWatcher newTextWatch = new SimpleTextWatcher() {
                @Override
                public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
                    listener.onChange();
                }
            };
            SimpleTextWatcher oldTextWatch = ListenerUtil.trackListener(customTextInputLayout, newTextWatch, R.id.textWatcher);
            if (oldTextWatch != null) {
                customTextInputLayout.removeTextWatch(oldTextWatch);
            }
            customTextInputLayout.addNotesTextWatch(newTextWatch);
        }
    }

}

自定义属性:

    
        
        
        
        
    

自定义控件:custom_text_input_layout



    

    


自定义EditText background:



    
    

自定义shape):bg_text_input_layout_foucs 和bg_text_input_normal



    
    
    




    
    
    

自定义EditText:MultipleLinesEditText
为什么要自定义一个EditText呢?因为如果EditeText编辑是多行的话,EditText需要可以内部滚动,我们就可以在这里进行滚动事件的处理。在CustomTextInputLayout处理这个监听是无效的

class MultipleLinesEditText : AppCompatEditText {

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (canScrollVertically(-1) || canScrollVertically(0)) {
            parent.requestDisallowInterceptTouchEvent(true)
        }
        return super.onTouchEvent(event)
    }
}

用法:

  

你可能感兴趣的:(Android,android,databinding)