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