Home | History | Annotate | Download | only in adapters
      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"})
     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"})
     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"})
     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"})
     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"})
     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"})
    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"})
    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"})
    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"})
    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"})
    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"})
    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"})
    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)
    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")
    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")
    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.
    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 {
    234         void onViewDetachedFromWindow(View v);
    235     }
    236 
    237     @TargetApi(VERSION_CODES.HONEYCOMB_MR1)
    238     public interface OnViewAttachedToWindow {
    239         void onViewAttachedToWindow(View v);
    240     }
    241 }
    242