Home | History | Annotate | Download | only in ui
      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.support.car.ui;
     17 
     18 import android.content.Context;
     19 import android.graphics.PorterDuff;
     20 import android.util.AttributeSet;
     21 import android.view.LayoutInflater;
     22 import android.view.View;
     23 import android.view.ViewGroup;
     24 import android.view.animation.AccelerateDecelerateInterpolator;
     25 import android.view.animation.Interpolator;
     26 import android.widget.FrameLayout;
     27 import android.widget.ImageView;
     28 
     29 /**
     30  * A custom view to provide list scroll behaviour -- up/down buttons and scroll indicator.
     31  *
     32  * @hide
     33  */
     34 public class PagedScrollBarView extends FrameLayout
     35         implements View.OnClickListener, View.OnLongClickListener {
     36     private static final float BUTTON_DISABLED_ALPHA = 0.2f;
     37 
     38     /**
     39      * Listener for when the list should paginate.
     40      */
     41     public interface PaginationListener {
     42         int PAGE_UP = 0;
     43         int PAGE_DOWN = 1;
     44 
     45         /** Called when the linked view should be paged in the given direction */
     46         void onPaginate(int direction);
     47     }
     48 
     49     private final ImageView mUpButton;
     50     private final ImageView mDownButton;
     51     private final ImageView mScrollThumb;
     52     /** The "filler" view between the up and down buttons */
     53     private final View mFiller;
     54     private final Interpolator mPaginationInterpolator = new AccelerateDecelerateInterpolator();
     55     private final int mMinThumbLength;
     56     private final int mMaxThumbLength;
     57     private PaginationListener mPaginationListener;
     58 
     59     public PagedScrollBarView(
     60             Context context, AttributeSet attrs) {
     61         this(context, attrs, 0 /*defStyleAttrs*/, 0 /*defStyleRes*/);
     62     }
     63 
     64     public PagedScrollBarView(
     65             Context context, AttributeSet attrs, int defStyleAttrs) {
     66         this(context, attrs, defStyleAttrs, 0 /*defStyleRes*/);
     67     }
     68 
     69     public PagedScrollBarView(
     70             Context context, AttributeSet attrs, int defStyleAttrs, int defStyleRes) {
     71         super(context, attrs, defStyleAttrs, defStyleRes);
     72 
     73         LayoutInflater inflater = (LayoutInflater) context
     74                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     75         inflater.inflate(
     76                 R.layout.car_paged_scrollbar_buttons, this /*root*/, true /*attachToRoot*/);
     77 
     78         mUpButton = (ImageView) findViewById(R.id.page_up);
     79         mUpButton.setImageDrawable(context.getDrawable(R.drawable.ic_up_button));
     80         mUpButton.setOnClickListener(this);
     81         mUpButton.setOnLongClickListener(this);
     82         mDownButton = (ImageView) findViewById(R.id.page_down);
     83         mDownButton.setImageDrawable(context.getDrawable(R.drawable.ic_down_button));
     84         mDownButton.setOnClickListener(this);
     85         mDownButton.setOnLongClickListener(this);
     86 
     87         mScrollThumb = (ImageView) findViewById(R.id.scrollbar_thumb);
     88         mScrollThumb.setAlpha(0.5f);
     89 
     90         mFiller = findViewById(R.id.filler);
     91 
     92         mMinThumbLength = getResources().getDimensionPixelSize(R.dimen.min_thumb_height);
     93         mMaxThumbLength = getResources().getDimensionPixelSize(R.dimen.max_thumb_height);
     94 
     95         if (!context.getResources().getBoolean(R.bool.car_true_for_touch)) {
     96             // Don't show the pagination buttons if there isn't touch.
     97             mUpButton.setVisibility(View.GONE);
     98             mDownButton.setVisibility(View.GONE);
     99         }
    100     }
    101 
    102     @Override
    103     public void onClick(View v) {
    104         dispatchPageClick(v);
    105     }
    106 
    107     @Override
    108     public boolean onLongClick(View v) {
    109         dispatchPageClick(v);
    110         return true;
    111     }
    112 
    113     public void setPaginationListener(PaginationListener listener) {
    114         mPaginationListener = listener;
    115     }
    116 
    117     /** Returns {@code true} if the "up" button is pressed */
    118     public boolean isUpPressed() {
    119         return mUpButton.isPressed();
    120     }
    121 
    122     /** Returns {@code true} if the "down" button is pressed */
    123     public boolean isDownPressed() {
    124         return mDownButton.isPressed();
    125     }
    126 
    127     /** Sets the range, offset and extent of the scroll bar. See {@link android.view.View}. */
    128     protected void setParameters(int range, int offset, int extent, boolean animate) {
    129         final int size = mFiller.getHeight() - mFiller.getPaddingTop() - mFiller.getPaddingBottom();
    130 
    131         int thumbLength = extent * size / range;
    132         thumbLength = Math.max(Math.min(thumbLength, mMaxThumbLength), mMinThumbLength);
    133 
    134         int thumbOffset = size - thumbLength;
    135         if (isDownEnabled()) {
    136             // We need to adjust the offset so that it fits into the possible space inside the
    137             // filler with regarding to the constraints set by mMaxThumbLength and mMinThumbLength.
    138             thumbOffset = (size - thumbLength) * offset / range;
    139         }
    140 
    141         // Sets the size of the thumb and request a redraw if needed.
    142         final ViewGroup.LayoutParams lp = mScrollThumb.getLayoutParams();
    143         if (lp.height != thumbLength) {
    144             lp.height = thumbLength;
    145             mScrollThumb.requestLayout();
    146         }
    147 
    148         moveY(mScrollThumb, thumbOffset, animate);
    149     }
    150 
    151     /** Sets auto day/night mode */
    152     protected void setAutoDayNightMode() {
    153         int color = getResources().getColor(R.color.car_tint);
    154         mUpButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    155         mUpButton.setBackgroundResource(R.drawable.car_pagination_background);
    156         mDownButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    157         mDownButton.setBackgroundResource(R.drawable.car_pagination_background);
    158 
    159         mScrollThumb.setBackgroundColor(color);
    160     }
    161 
    162     /** Sets auto light mode */
    163     protected void setLightMode() {
    164         int color = getResources().getColor(R.color.car_tint_light);
    165         mUpButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    166         mUpButton.setBackgroundResource(R.drawable.car_pagination_background_light);
    167         mDownButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    168         mDownButton.setBackgroundResource(R.drawable.car_pagination_background_light);
    169 
    170         mScrollThumb.setBackgroundColor(color);
    171     }
    172 
    173     /** Sets auto dark mode */
    174     protected void setDarkMode() {
    175         int color = getResources().getColor(R.color.car_tint_dark);
    176         mUpButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    177         mUpButton.setBackgroundResource(R.drawable.car_pagination_background_dark);
    178         mDownButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    179         mDownButton.setBackgroundResource(R.drawable.car_pagination_background_dark);
    180 
    181         mScrollThumb.setBackgroundColor(color);
    182     }
    183 
    184     protected void setUpEnabled(boolean enabled) {
    185         mUpButton.setEnabled(enabled);
    186         mUpButton.setAlpha(enabled ? 1f : BUTTON_DISABLED_ALPHA);
    187     }
    188 
    189     protected void setDownEnabled(boolean enabled) {
    190         mDownButton.setEnabled(enabled);
    191         mDownButton.setAlpha(enabled ? 1f : BUTTON_DISABLED_ALPHA);
    192     }
    193 
    194     protected boolean isDownEnabled() {
    195         return mDownButton.isEnabled();
    196     }
    197 
    198     private void dispatchPageClick(View v) {
    199         final PaginationListener listener = mPaginationListener;
    200         if (listener == null) {
    201             return;
    202         }
    203 
    204         final int direction = (v.getId() == R.id.page_up)
    205                 ? PaginationListener.PAGE_UP : PaginationListener.PAGE_DOWN;
    206         listener.onPaginate(direction);
    207     }
    208 
    209     /** Moves the given view to the specified 'y' position. */
    210     private void moveY(final View view, float newPosition, boolean animate) {
    211         final int duration = animate ? 200 : 0;
    212         view.animate()
    213                 .y(newPosition)
    214                 .setDuration(duration)
    215                 .setInterpolator(mPaginationInterpolator)
    216                 .start();
    217     }
    218 }