/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.wear.widget; import android.content.Context; import android.support.annotation.Nullable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; /** * This wear-specific implementation of {@link LinearLayoutManager} provides basic * offsetting logic for updating child layout. For round devices it offsets the children * horizontally to make them appear to travel around a circle. For square devices it aligns them in * a straight list. This functionality is provided by the {@link CurvingLayoutCallback} which is * set when constructing the this class with its default constructor * {@link #WearableLinearLayoutManager(Context)}. */ public class WearableLinearLayoutManager extends LinearLayoutManager { @Nullable private LayoutCallback mLayoutCallback; /** * Callback for interacting with layout passes. */ public abstract static class LayoutCallback { /** * Override this method to implement custom child layout behavior on scroll. It is called * at the end of each layout pass of the view (including scrolling) and enables you to * modify any property of the child view. Examples include scaling the children based on * their distance from the center of the parent, or changing the translation of the children * to create an illusion of the path they are moving along. * * @param child the current child to be affected. * @param parent the {@link RecyclerView} parent that this class is attached to. */ public abstract void onLayoutFinished(View child, RecyclerView parent); } /** * Creates a {@link WearableLinearLayoutManager} for a vertical list. * * @param context Current context, will be used to access resources. * @param layoutCallback Callback to be associated with this {@link WearableLinearLayoutManager} */ public WearableLinearLayoutManager(Context context, LayoutCallback layoutCallback) { super(context, VERTICAL, false); mLayoutCallback = layoutCallback; } /** * Creates a {@link WearableLinearLayoutManager} for a vertical list. * * @param context Current context, will be used to access resources. */ public WearableLinearLayoutManager(Context context) { this(context, new CurvingLayoutCallback(context)); } /** * Set a particular instance of the layout callback for this * {@link WearableLinearLayoutManager}. The callback will be called on the Ui thread. * * @param layoutCallback */ public void setLayoutCallback(@Nullable LayoutCallback layoutCallback) { mLayoutCallback = layoutCallback; } /** * @return the current {@link LayoutCallback} associated with this * {@link WearableLinearLayoutManager}. */ @Nullable public LayoutCallback getLayoutCallback() { return mLayoutCallback; } @Override public int scrollVerticallyBy( int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { int scrolled = super.scrollVerticallyBy(dy, recycler, state); updateLayout(); return scrolled; } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { super.onLayoutChildren(recycler, state); if (getChildCount() == 0) { return; } updateLayout(); } private void updateLayout() { if (mLayoutCallback == null) { return; } final int childCount = getChildCount(); for (int count = 0; count < childCount; count++) { View child = getChildAt(count); mLayoutCallback.onLayoutFinished(child, (WearableRecyclerView) child.getParent()); } } }