Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2018 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 com.android.launcher3.util;
     17 
     18 import android.animation.ArgbEvaluator;
     19 import android.animation.ObjectAnimator;
     20 import android.animation.ValueAnimator;
     21 import android.graphics.Color;
     22 import android.graphics.drawable.ColorDrawable;
     23 import android.graphics.drawable.Drawable;
     24 import android.support.v4.graphics.ColorUtils;
     25 import android.view.View;
     26 import android.view.View.OnLayoutChangeListener;
     27 import android.widget.AbsListView;
     28 import android.widget.AbsListView.OnScrollListener;
     29 import android.widget.AbsListView.RecyclerListener;
     30 import android.widget.ListView;
     31 
     32 import com.android.launcher3.R;
     33 
     34 /**
     35  * Utility class to scroll and highlight a list view item
     36  */
     37 public class ListViewHighlighter implements OnScrollListener, RecyclerListener,
     38         OnLayoutChangeListener {
     39 
     40     private final ListView mListView;
     41     private int mPosHighlight;
     42 
     43     private boolean mColorAnimated = false;
     44 
     45     public ListViewHighlighter(ListView listView, int posHighlight) {
     46         mListView = listView;
     47         mPosHighlight = posHighlight;
     48         mListView.setOnScrollListener(this);
     49         mListView.setRecyclerListener(this);
     50         mListView.addOnLayoutChangeListener(this);
     51 
     52         mListView.post(this::tryHighlight);
     53     }
     54 
     55     @Override
     56     public void onLayoutChange(View v, int left, int top, int right, int bottom,
     57             int oldLeft, int oldTop, int oldRight, int oldBottom) {
     58         mListView.post(this::tryHighlight);
     59     }
     60 
     61     private void tryHighlight() {
     62         if (mPosHighlight < 0 || mListView.getChildCount() == 0) {
     63             return;
     64         }
     65         if (!highlightIfVisible(mListView.getFirstVisiblePosition(),
     66                 mListView.getLastVisiblePosition())) {
     67             mListView.smoothScrollToPosition(mPosHighlight);
     68         }
     69     }
     70 
     71     @Override
     72     public void onScrollStateChanged(AbsListView absListView, int i) { }
     73 
     74     @Override
     75     public void onScroll(AbsListView view, int firstVisibleItem,
     76             int visibleItemCount, int totalItemCount) {
     77         highlightIfVisible(firstVisibleItem, firstVisibleItem + visibleItemCount);
     78     }
     79 
     80     private boolean highlightIfVisible(int start, int end) {
     81         if (mPosHighlight < 0 || mListView.getChildCount() == 0) {
     82             return false;
     83         }
     84         if (start > mPosHighlight || mPosHighlight > end) {
     85             return false;
     86         }
     87         highlightView(mListView.getChildAt(mPosHighlight - start));
     88 
     89         // finish highlight
     90         mListView.setOnScrollListener(null);
     91         mListView.removeOnLayoutChangeListener(this);
     92 
     93         mPosHighlight = -1;
     94         return true;
     95     }
     96 
     97     @Override
     98     public void onMovedToScrapHeap(View view) {
     99         unhighlightView(view);
    100     }
    101 
    102     private void highlightView(View view) {
    103         if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
    104             // already highlighted
    105         } else {
    106             view.setTag(R.id.view_highlighted, true);
    107             view.setTag(R.id.view_unhighlight_background, view.getBackground());
    108             view.setBackground(getHighlightBackground());
    109             view.postDelayed(() -> {
    110                 unhighlightView(view);
    111             }, 15000L);
    112         }
    113     }
    114 
    115     private void unhighlightView(View view) {
    116         if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
    117             Object background = view.getTag(R.id.view_unhighlight_background);
    118             if (background instanceof Drawable) {
    119                 view.setBackground((Drawable) background);
    120             }
    121             view.setTag(R.id.view_unhighlight_background, null);
    122             view.setTag(R.id.view_highlighted, false);
    123         }
    124     }
    125 
    126     private ColorDrawable getHighlightBackground() {
    127         int color = ColorUtils.setAlphaComponent(Themes.getColorAccent(mListView.getContext()), 26);
    128         if (mColorAnimated) {
    129             return new ColorDrawable(color);
    130         }
    131         mColorAnimated = true;
    132         ColorDrawable bg = new ColorDrawable(Color.WHITE);
    133         ObjectAnimator anim = ObjectAnimator.ofInt(bg, "color", Color.WHITE, color);
    134         anim.setEvaluator(new ArgbEvaluator());
    135         anim.setDuration(200L);
    136         anim.setRepeatMode(ValueAnimator.REVERSE);
    137         anim.setRepeatCount(4);
    138         anim.start();
    139         return bg;
    140     }
    141 }
    142