ViewBindingAdapter.java revision c7cd9c61e55b43b712d20f855ca59d6fbc49e5b1
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.databinding.adapters;
17
18import android.annotation.TargetApi;
19import android.databinding.BindingAdapter;
20import android.databinding.BindingMethod;
21import android.databinding.BindingMethods;
22import android.os.Build;
23import android.os.Build.VERSION;
24import android.os.Build.VERSION_CODES;
25import android.view.View;
26import android.view.View.OnAttachStateChangeListener;
27import com.android.databinding.library.baseAdapters.R;
28
29@BindingMethods({
30        @BindingMethod(type = View.class, attribute = "android:backgroundTint", method = "setBackgroundTintList"),
31        @BindingMethod(type = View.class, attribute = "android:fadeScrollbars", method = "setScrollbarFadingEnabled"),
32        @BindingMethod(type = View.class, attribute = "android:getOutline", method = "setOutlineProvider"),
33        @BindingMethod(type = View.class, attribute = "android:nextFocusForward", method = "setNextFocusForwardId"),
34        @BindingMethod(type = View.class, attribute = "android:nextFocusLeft", method = "setNextFocusLeftId"),
35        @BindingMethod(type = View.class, attribute = "android:nextFocusRight", method = "setNextFocusRightId"),
36        @BindingMethod(type = View.class, attribute = "android:nextFocusUp", method = "setNextFocusUpId"),
37        @BindingMethod(type = View.class, attribute = "android:nextFocusDown", method = "setNextFocusDownId"),
38        @BindingMethod(type = View.class, attribute = "android:requiresFadingEdge", method = "setVerticalFadingEdgeEnabled"),
39        @BindingMethod(type = View.class, attribute = "android:scrollbarDefaultDelayBeforeFade", method = "setScrollBarDefaultDelayBeforeFade"),
40        @BindingMethod(type = View.class, attribute = "android:scrollbarFadeDuration", method = "setScrollBarFadeDuration"),
41        @BindingMethod(type = View.class, attribute = "android:scrollbarSize", method = "setScrollBarSize"),
42        @BindingMethod(type = View.class, attribute = "android:scrollbarStyle", method = "setScrollBarStyle"),
43        @BindingMethod(type = View.class, attribute = "android:transformPivotX", method = "setPivotX"),
44        @BindingMethod(type = View.class, attribute = "android:transformPivotY", method = "setPivotY"),
45        @BindingMethod(type = View.class, attribute = "android:onDrag", method = "setOnDragListener"),
46        @BindingMethod(type = View.class, attribute = "android:onClick", method = "setOnClickListener"),
47        @BindingMethod(type = View.class, attribute = "android:onApplyWindowInsets", method = "setOnApplyWindowInsetsListener"),
48        @BindingMethod(type = View.class, attribute = "android:onCreateContextMenu", method = "setOnCreateContextMenuListener"),
49        @BindingMethod(type = View.class, attribute = "android:onFocusChange", method = "setOnFocusChangeListener"),
50        @BindingMethod(type = View.class, attribute = "android:onGenericMotion", method = "setOnGenericMotionListener"),
51        @BindingMethod(type = View.class, attribute = "android:onHover", method = "setOnHoverListener"),
52        @BindingMethod(type = View.class, attribute = "android:onKey", method = "setOnKeyListener"),
53        @BindingMethod(type = View.class, attribute = "android:onLongClick", method = "setOnLongClickListener"),
54        @BindingMethod(type = View.class, attribute = "android:onSystemUiVisibilityChange", method = "setOnSystemUiVisibilityChangeListener"),
55        @BindingMethod(type = View.class, attribute = "android:onTouch", method = "setOnTouchListener"),
56})
57public class ViewBindingAdapter {
58    public static int FADING_EDGE_NONE = 0;
59    public static int FADING_EDGE_HORIZONTAL = 1;
60    public static int FADING_EDGE_VERTICAL = 2;
61
62    @BindingAdapter({"android:padding"})
63    public static void setPadding(View view, float paddingFloat) {
64        final int padding = pixelsToDimensionPixelSize(paddingFloat);
65        view.setPadding(padding, padding, padding, padding);
66    }
67
68    @BindingAdapter({"android:paddingBottom"})
69    public static void setPaddingBottom(View view, float paddingFloat) {
70        final int padding = pixelsToDimensionPixelSize(paddingFloat);
71        view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
72                padding);
73    }
74
75    @BindingAdapter({"android:paddingEnd"})
76    public static void setPaddingEnd(View view, float paddingFloat) {
77        final int padding = pixelsToDimensionPixelSize(paddingFloat);
78        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
79            view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), padding,
80                    view.getPaddingBottom());
81        } else {
82            view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding,
83                    view.getPaddingBottom());
84        }
85    }
86
87    @BindingAdapter({"android:paddingLeft"})
88    public static void setPaddingLeft(View view, float paddingFloat) {
89        final int padding = pixelsToDimensionPixelSize(paddingFloat);
90        view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(),
91                view.getPaddingBottom());
92    }
93
94    @BindingAdapter({"android:paddingRight"})
95    public static void setPaddingRight(View view, float paddingFloat) {
96        final int padding = pixelsToDimensionPixelSize(paddingFloat);
97        view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding,
98                view.getPaddingBottom());
99    }
100
101    @BindingAdapter({"android:paddingStart"})
102    public static void setPaddingStart(View view, float paddingFloat) {
103        final int padding = pixelsToDimensionPixelSize(paddingFloat);
104        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
105            view.setPaddingRelative(padding, view.getPaddingTop(), view.getPaddingEnd(),
106                    view.getPaddingBottom());
107        } else {
108            view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(),
109                    view.getPaddingBottom());
110        }
111    }
112
113    @BindingAdapter({"android:paddingTop"})
114    public static void setPaddingTop(View view, float paddingFloat) {
115        final int padding = pixelsToDimensionPixelSize(paddingFloat);
116        view.setPadding(view.getPaddingLeft(), padding, view.getPaddingRight(),
117                view.getPaddingBottom());
118    }
119
120    @BindingAdapter({"android:requiresFadingEdge"})
121    public static void setRequiresFadingEdge(View view, int value) {
122        final boolean vertical = (value & FADING_EDGE_VERTICAL) != 0;
123        final boolean horizontal = (value & FADING_EDGE_HORIZONTAL) != 0;
124        view.setVerticalFadingEdgeEnabled(vertical);
125        view.setHorizontalFadingEdgeEnabled(horizontal);
126    }
127
128    @BindingAdapter({"android:onClickListener", "android:clickable"})
129    public static void setClickListener(View view, View.OnClickListener clickListener,
130            boolean clickable) {
131        view.setOnClickListener(clickListener);
132        view.setClickable(clickable);
133    }
134
135    @BindingAdapter({"android:onClick", "android:clickable"})
136    public static void setOnClick(View view, View.OnClickListener clickListener,
137            boolean clickable) {
138        view.setOnClickListener(clickListener);
139        view.setClickable(clickable);
140    }
141
142    @BindingAdapter({"android:onLongClickListener", "android:longClickable"})
143    public static void setOnLongClickListener(View view, View.OnLongClickListener clickListener,
144            boolean clickable) {
145        view.setOnLongClickListener(clickListener);
146        view.setLongClickable(clickable);
147    }
148
149    @BindingAdapter({"android:onLongClick", "android:longClickable"})
150    public static void setOnLongClick(View view, View.OnLongClickListener clickListener,
151            boolean clickable) {
152        view.setOnLongClickListener(clickListener);
153        view.setLongClickable(clickable);
154    }
155
156    @BindingAdapter(value = {"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"},
157            requireAll = false)
158    public static void setOnAttachStateChangeListener(View view,
159            final OnViewDetachedFromWindow detach, final OnViewAttachedToWindow attach) {
160        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
161            final OnAttachStateChangeListener newListener;
162            if (detach == null && attach == null) {
163                newListener = null;
164            } else {
165                newListener = new OnAttachStateChangeListener() {
166                    @Override
167                    public void onViewAttachedToWindow(View v) {
168                        if (attach != null) {
169                            attach.onViewAttachedToWindow(v);
170                        }
171                    }
172
173                    @Override
174                    public void onViewDetachedFromWindow(View v) {
175                        if (detach != null) {
176                            detach.onViewDetachedFromWindow(v);
177                        }
178                    }
179                };
180            }
181            final OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view,
182                    newListener, R.id.onAttachStateChangeListener);
183            if (oldListener != null) {
184                view.removeOnAttachStateChangeListener(oldListener);
185            }
186            if (newListener != null) {
187                view.addOnAttachStateChangeListener(newListener);
188            }
189        }
190    }
191
192    @BindingAdapter("android:onLayoutChange")
193    public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,
194            View.OnLayoutChangeListener newValue) {
195        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
196            if (oldValue != null) {
197                view.removeOnLayoutChangeListener(oldValue);
198            }
199            if (newValue != null) {
200                view.addOnLayoutChangeListener(newValue);
201            }
202        }
203    }
204
205    // Follows the same conversion mechanism as in TypedValue.complexToDimensionPixelSize as used
206    // when setting padding. It rounds off the float value unless the value is < 1.
207    // When a value is between 0 and 1, it is set to 1. A value less than 0 is set to -1.
208    private static int pixelsToDimensionPixelSize(float pixels) {
209        final int result = (int) (pixels + 0.5f);
210        if (result != 0) {
211            return result;
212        } else if (pixels == 0) {
213            return 0;
214        } else if (pixels > 0) {
215            return 1;
216        } else {
217            return -1;
218        }
219    }
220
221    @TargetApi(VERSION_CODES.HONEYCOMB_MR1)
222    public interface OnViewDetachedFromWindow {
223        void onViewDetachedFromWindow(View v);
224    }
225
226    @TargetApi(VERSION_CODES.HONEYCOMB_MR1)
227    public interface OnViewAttachedToWindow {
228        void onViewAttachedToWindow(View v);
229    }
230}
231