com.facebook.litho.utils.IncrementalMountUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.litho.utils.IncrementalMountUtils.java

Source

/**
 * Copyright (c) 2017-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.litho.utils;

import android.graphics.Rect;
import android.support.v4.util.Pools;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import com.facebook.litho.LithoView;
import com.facebook.litho.config.ComponentsConfiguration;

import static com.facebook.litho.ThreadUtils.assertMainThread;

/**
 * Provides methods for enabling incremental mount.
 */
public class IncrementalMountUtils {

    /**
     * A view that wraps a child view and that provides a wrapped view to be incrementally mounted.
     */
    public interface WrapperView {

        /**
         * @return A child view that will be incrementally mounted.
         */
        View getWrappedView();
    }

    private static final Pools.SynchronizedPool<Rect> sRectPool = new Pools.SynchronizedPool<>(10);

    /**
     * Performs incremental mount on the children views of the given ViewGroup.
     * @param scrollingViewParent ViewGroup container of views that will be incrementally mounted.
     */
    public static void performIncrementalMount(ViewGroup scrollingViewParent) {
        performIncrementalMount(scrollingViewParent, /* force */ false);
    }

    /**
     * Performs incremental mount on the children views of the given ViewGroup.
     * @param scrollingViewParent ViewGroup container of views that will be incrementally mounted.
     * @param force whether the incremental mount should always take place, or only if
     * {@link ComponentsConfiguration.isIncrementalMountOnOffsetOrTranslationChangeEnabled} returns
     * false.
     */
    public static void performIncrementalMount(ViewGroup scrollingViewParent, boolean force) {
        assertMainThread();

        if (!force && ComponentsConfiguration.isIncrementalMountOnOffsetOrTranslationChangeEnabled) {
            return;
        }

        final int viewGroupWidth = scrollingViewParent.getWidth();
        final int viewGroupHeight = scrollingViewParent.getHeight();
        for (int i = 0; i < scrollingViewParent.getChildCount(); i++) {
            maybePerformIncrementalMountOnView(viewGroupWidth, viewGroupHeight, scrollingViewParent.getChildAt(i));
        }
    }

    /**
     * Returns a scroll listener that performs incremental mount.  This is needed
     * for feeds that do not use a ScrollingViewProxy, but rather directly use a
     * RecyclerView.
    */
    public static RecyclerView.OnScrollListener createRecyclerViewListener() {
        return new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                performIncrementalMount(recyclerView);
            }
        };
    }

    private static void maybePerformIncrementalMountOnView(int scrollingParentWidth, int scrollingParentHeight,
            View view) {
        final View underlyingView = view instanceof WrapperView ? ((WrapperView) view).getWrappedView() : view;

        if (!(underlyingView instanceof LithoView)) {
            return;
        }

        final LithoView lithoView = (LithoView) underlyingView;
        if (!lithoView.isIncrementalMountEnabled()) {
            return;
        }

        if (view != underlyingView && view.getHeight() != underlyingView.getHeight()) {
            throw new IllegalStateException(
                    "ViewDiagnosticsWrapper must be the same height as the underlying view");
        }

        final int translationX = (int) view.getTranslationX();
        final int translationY = (int) view.getTranslationY();
        final int top = view.getTop() + translationY;
        final int bottom = view.getBottom() + translationY;
        final int left = view.getLeft() + translationX;
        final int right = view.getRight() + translationX;

        if (left >= 0 && top >= 0 && right <= scrollingParentWidth && bottom <= scrollingParentHeight
                && lithoView.getPreviousMountBounds().width() == lithoView.getWidth()
                && lithoView.getPreviousMountBounds().height() == lithoView.getHeight()) {
            // View is fully visible, and has already been completely mounted.
            return;
        }

        final Rect rect = acquireRect();
        rect.set(Math.max(0, -left), Math.max(0, -top), Math.min(right, scrollingParentWidth) - left,
                Math.min(bottom, scrollingParentHeight) - top);

        if (rect.isEmpty()) {
            // View is not visible at all, nothing to do.
            release(rect);
            return;
        }

        lithoView.performIncrementalMount(rect);

        release(rect);
    }

    private static Rect acquireRect() {
        Rect rect = sRectPool.acquire();
        if (rect == null) {
            rect = new Rect();
        }

        return rect;
    }

    private static void release(Rect rect) {
        rect.setEmpty();
        sRectPool.release(rect);
    }
}