美文网首页
DataBinding自定义adapter

DataBinding自定义adapter

作者: 麻油里 | 来源:发表于2019-03-27 22:32 被阅读0次

    DataBinding支持使用自定义的方法来处理View。

    自动检测自定义方法

    假设现在有一个自定义View,其中有一个自定义方法setMyViewBgColor。

    public class MyView extends AppCompatTextView {
        public MyView(Context context) {
            super(context);
        }
    
        public MyView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public void setMyViewBgColor(int color) {
            setBackgroundColor(color);
        }
    }
    

    在xml中

    <com.qianfanyun.databinding.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="aaaa"
        app:myViewBgColor="@{@color/colorPrimary}"
        />
    

    这时会发现,界面上View的背景变成了colorPrimary的颜色。

    DataBinding会自动检测View中的set方法,如果与自定义属性的名称和参数一致,会进行调用。这个还是很方便的,省去了我们定义自定义属性的时间。

    自定义关联的属性和方法,这样对方法命名就没有强制要求了

    @BindingMethods({
            @BindingMethod(type = MyView.class,
                    attribute = "bg",
                    method = "setMyViewBgColor"),
    })
    
    public class MyView extends AppCompatTextView {
    
    
        public MyView(Context context) {
            super(context);
        }
    
        public MyView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public void setMyViewBgColor(int color) {
            setBackgroundColor(color);
        }
    }
    

    自定义方法处理xml中的属性

    DataBinding运行自定义方法,对应xml中的自定义属性。下面以图片加载为例

    首先创建一个工具类,添加注释@BindingAdapter。value表示自定义属性的名称,从方法第二个参数开始一一对应。第一个参数表示哪种类型的View支持这个自定义方法。

    public class ImageUtil {
    
        @BindingAdapter(value = {"image"})
        public static void loadImage(ImageView imageView, String url) {
            ImageLoader.get().loadImage(imageView, url);
        }
    }
    
    
    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:image='@{"https://ws1.sinaimg.cn/large/0065oQSqly1g0ajj4h6ndj30sg11xdmj.jpg"}'
         />
    

    这样,网络图片就成功加载出来了。

    这种方式也支持多个参数

    @BindingAdapter(value = {"image","round"}, requireAll = false)
    public static void loadImage(ImageView imageView, String url, boolean round) {
        if (round) {
            ImageLoader.get().loadImage(imageView, url, ImageOptions.option().circleCrop().build());
        } else {
            ImageLoader.get().loadImage(imageView, url);
        }
    }
    

    requireAll表示是否所有参数都必须填

    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:image='@{"https://ws1.sinaimg.cn/large/0065oQSqly1g0ajj4h6ndj30sg11xdmj.jpg"}'
        app:round="@{true}" />
    

    这样加载出来的就是圆形图片

    实际上,通过这种方式,可以解决使用Glide加载图片时,无法在xml中定义属性的问题,通过预定义各种参数,可以将Glide所有支持的属性,在xml中实现。

    监听拓展

    DataBinding可以对View原有的监听进行拓展。这里举两个例子

    • 支持在xml中调用任意类的方法处理OnTextChanged事件。
    • 防止多次点击的OnClick实现。

    case 1

    定义一个处理android:onTextChanged的方法。

    public class AdapterUtils {
    
        @BindingAdapter("android:onTextChanged")
        public static void setTextChangedListener(EditText editText, final OnTextChangedListener listener) {
            if (listener != null) {
                TextWatcher textWatcher = new TextWatcher() {
                    @Override
                    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
                    }
    
                    @Override
                    public void onTextChanged(CharSequence s, int start, int before, int count) {
                        listener.onTextChanged(s.toString());
                    }
    
                    @Override
                    public void afterTextChanged(Editable s) {
    
                    }
                };
                TextWatcher oldWatcher = ListenerUtil.trackListener(editText, textWatcher, R.id.textWatcher);
                if (oldWatcher != null) {
                    editText.removeTextChangedListener(oldWatcher);
                } else {
                    editText.addTextChangedListener(textWatcher);
                }
            }
        }
    }
    

    第二个参数是我们自定义的一个接口。DataBinding只支持单一方法的接口,因此自定义了一个新的接口。

    public interface OnTextChangedListener {
        void onTextChanged(String text);
    }
    
    public class MainActivity extends AppCompatActivity {
    
        ActivityMainBinding binding;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            binding.setMainActivity(this);
        }
    
    
        public void onTextChanged(String str){
            Log.d("x","onTextChanged--->"+str);
        }
    
    }
    
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        tools:context=".MainActivity">
    
        <data>
    
            <variable
                name="MainActivity"
                type="com.qianfanyun.databinding.MainActivity" />
    
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_horizontal"
            android:orientation="vertical">
    
            <EditText
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:onTextChanged="@{(str)->MainActivity.onTextChanged(str)}" />
    
        </LinearLayout>
    </layout>
    

    最终在text改变时,会输出当前的text。

    这样看起来代码更多了。但实际上这个adapter可以是通用的,以后所有的OnTextChanged只需要在某个类中定义一个公共方法,并在xml中引用即可。

    case 2

    定义一个代理方法。使用工具方法判断是否在短时间内重复点击。

        @BindingAdapter("android:onClick")
        public static void setClickListener(View view, final View.OnClickListener listener){
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (Utils.isFastDoubleClick()){
                        return;
                    }
                    listener.onClick(v);
                }
            });
        }
    

    工具方法

    public class Utils {
    
        private static long lastClickTime;
    
        public static boolean isFastDoubleClick() {
            long time = System.currentTimeMillis();
            long timeD = time - lastClickTime;
            if (0 < timeD && timeD < 800) {
                return true;
            }
            lastClickTime = time;
            return false;
        }
    
    }
    

    在xml中调用方法

    <Button
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="Button"
        android:onClick="@{()->MainActivity.onButtonClick()}"
         />
    

    在MainActivity中定义

    public void onButtonClick(){
        Log.d("x","onClick");
    }
    

    测试下来确实短时间内快速点击不会重复触发点击事件

    总结

    总体来说,DataBinding支持3种方式对xml中的属性进行拓展

    • View的自定义方法
      • set前缀自动识别
      • 手动绑定属性和自定义方法
    • Adapter自定义View的属性
      • 支持自定义属性名
      • 自定义处理属性的方法
      • 支持多个属性作为方法的参数
    • Adapter拓展View原有的监听
      • 只支持单个函数的接口
      • 可以实现对原有监听的拦截

    相关文章

      网友评论

          本文标题:DataBinding自定义adapter

          本文链接:https://www.haomeiwen.com/subject/uaexbqtx.html