1 /* 2 * Copyright (C) 2021 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.widget.picker; 17 18 import static android.view.View.MeasureSpec.EXACTLY; 19 import static android.view.View.MeasureSpec.makeMeasureSpec; 20 21 import android.content.Context; 22 import android.view.View; 23 import android.view.ViewGroup; 24 25 import androidx.recyclerview.widget.RecyclerView.ViewHolder; 26 27 import com.android.launcher3.recyclerview.ViewHolderBinder; 28 import com.android.launcher3.widget.model.WidgetListSpaceEntry; 29 30 import java.util.List; 31 import java.util.function.IntSupplier; 32 33 /** 34 * {@link ViewHolderBinder} for binding the top empty space 35 */ 36 public class WidgetsSpaceViewHolderBinder 37 implements ViewHolderBinder<WidgetListSpaceEntry, ViewHolder> { 38 39 private final IntSupplier mEmptySpaceHeightProvider; 40 WidgetsSpaceViewHolderBinder(IntSupplier emptySpaceHeightProvider)41 public WidgetsSpaceViewHolderBinder(IntSupplier emptySpaceHeightProvider) { 42 mEmptySpaceHeightProvider = emptySpaceHeightProvider; 43 } 44 45 @Override newViewHolder(ViewGroup parent)46 public ViewHolder newViewHolder(ViewGroup parent) { 47 return new ViewHolder(new EmptySpaceView(parent.getContext())) { }; 48 } 49 50 @Override bindViewHolder(ViewHolder holder, WidgetListSpaceEntry data, @ListPosition int position, List<Object> payloads)51 public void bindViewHolder(ViewHolder holder, WidgetListSpaceEntry data, 52 @ListPosition int position, List<Object> payloads) { 53 ((EmptySpaceView) holder.itemView).setFixedHeight(mEmptySpaceHeightProvider.getAsInt()); 54 } 55 56 /** 57 * Empty view which allows listening for 'Y' changes 58 */ 59 public static class EmptySpaceView extends View { 60 61 private Runnable mOnYChangeCallback; 62 private int mHeight = 0; 63 EmptySpaceView(Context context)64 private EmptySpaceView(Context context) { 65 super(context); 66 animate().setUpdateListener(v -> notifyYChanged()); 67 } 68 69 /** 70 * Sets the height for the empty view 71 * @return true if the height changed, false otherwise 72 */ setFixedHeight(int height)73 public boolean setFixedHeight(int height) { 74 if (mHeight != height) { 75 mHeight = height; 76 requestLayout(); 77 return true; 78 } 79 return false; 80 } 81 82 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)83 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 84 super.onMeasure(widthMeasureSpec, makeMeasureSpec(mHeight, EXACTLY)); 85 } 86 setOnYChangeCallback(Runnable callback)87 public void setOnYChangeCallback(Runnable callback) { 88 mOnYChangeCallback = callback; 89 } 90 91 @Override onLayout(boolean changed, int left, int top, int right, int bottom)92 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 93 super.onLayout(changed, left, top, right, bottom); 94 notifyYChanged(); 95 } 96 97 @Override offsetTopAndBottom(int offset)98 public void offsetTopAndBottom(int offset) { 99 super.offsetTopAndBottom(offset); 100 notifyYChanged(); 101 } 102 103 @Override setTranslationY(float translationY)104 public void setTranslationY(float translationY) { 105 super.setTranslationY(translationY); 106 notifyYChanged(); 107 } 108 notifyYChanged()109 private void notifyYChanged() { 110 if (mOnYChangeCallback != null) { 111 mOnYChangeCallback.run(); 112 } 113 } 114 } 115 } 116