com.github.omadahealth.slidepager.lib.SlideTransformer.java Source code

Java tutorial

Introduction

Here is the source code for com.github.omadahealth.slidepager.lib.SlideTransformer.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Omada Health, Inc
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.github.omadahealth.slidepager.lib;

import android.content.res.TypedArray;
import android.support.v4.view.ViewPager;
import android.view.View;

import com.github.omadahealth.slidepager.lib.views.SelectedImageView;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * This Transformer allows to apply different ratios to different {@link android.view.View} in the
 * {@link android.support.v4.view.ViewPager} pages.
 * <p/>
 * Created by oliviergoutay and stoyand on 4/1/15.
 */
public class SlideTransformer implements ViewPager.PageTransformer {
    /**
     * The tag for logging
     */
    private static final String TAG = "SlideTransformer";

    /**
     * The default ratio to apply translations with.
     */
    public static final Float DEFAULT_TRANSLATION_RATIO = 1.0f;

    /**
     * The {@link LinkedHashMap} that contains all the ratio to appy to the view resourceIds
     */
    private static LinkedHashMap<Integer, Ratio> mRatios;

    /**
     * Allows to save the last position of the {@link android.view.View} to deduce the current direction of the swipe.
     * Used in {@link #transformPage(android.view.View, float)}
     */
    private float lastPosition = 0f;

    /**
     * Modified in {@link #transformPage(android.view.View, float)} by using {@link #lastPosition} to know the direction of the swipe.
     */
    private boolean swipingRight = false;

    /**
     * This method allows to create a Slide effect on the {@link android.support.v4.view.ViewPager} transitions.
     * You need to implement this class and implement the {@link #getViewRatios()} method, providing a map between
     * view-id and ratio.
     *
     * @param view     The {@link android.view.View} currently animating
     * @param position The position reached by this view
     */
    @SuppressWarnings("unchecked")
    @Override
    public void transformPage(View view, float position) {
        if (view == null) {
            return;
        }

        if (view.getTag(R.id.slide_transformer_tag_key) == null
                || !(view.getTag(R.id.slide_transformer_tag_key) instanceof List)) {
            initTags(view);
        }

        swipingRight = lastPosition < position;
        lastPosition = position;
        //Stop the root page from moving during animation
        lockPage(view, position);

        if (view.getTag(R.id.slide_transformer_tag_key) instanceof List) {
            List<View> children = (List<View>) view.getTag(R.id.slide_transformer_tag_key);

            if (getViewRatios() != null) {
                for (View child : children) {
                    int id = child instanceof SelectedImageView ? ((SelectedImageView) child).getSelectedViewId()
                            : child.getId();
                    float ratio = getViewRatios().containsKey(child.getId())
                            ? getViewRatios().get(id).getRatio(swipingRight)
                            : DEFAULT_TRANSLATION_RATIO;
                    float translation = position * ((float) view.getWidth() / ratio);
                    if (child instanceof SelectedImageView) {
                        Float offset = (Float) child.getTag(R.id.selected_day_image_view);
                        if (offset == null) {
                            offset = 0f;
                        }
                        translation += offset;
                    }
                    child.setTranslationX(translation);
                }
            }
        } else {
            throw new IllegalArgumentException("Tags are not set properly");
        }
    }

    /**
     * Init the view tags to improve performances ==> it will call {@link android.view.View#findViewById(int)}
     * only once per View.
     *
     * @param view The {@link android.view.View} we want to search for the ids get into {@link #getViewRatios()} as the keys
     */
    public static void initTags(View view) {
        List<View> subViews = new ArrayList<>();
        if (getViewRatios() != null) {
            for (Map.Entry<Integer, Ratio> entry : getViewRatios().entrySet()) {
                View subView = view.findViewById(entry.getKey());
                if (subView != null) {
                    subViews.add(subView);
                }
            }
        }

        view.setTag(R.id.slide_transformer_tag_key, subViews);
    }

    /**
     * Override this method to return a {@link java.util.HashMap} of the resource ID's of each view
     * as a key and the scaling for it's translation int {@link #transformPage(android.view.View, float)}.
     * If the view is not in the map, then its translation ratio defaults to {@link #DEFAULT_TRANSLATION_RATIO}
     * </p>
     *
     * @return The map of the view-id/translation-ratio
     */
    public static LinkedHashMap<Integer, Ratio> getViewRatios() {
        if (mRatios == null) {
            mRatios = new LinkedHashMap<>();
            mRatios.put(R.id.left_text_view, new Ratio(4.0f, 1.0f));
            mRatios.put(R.id.right_text_view, new Ratio(1.0f, 4.0f));

            mRatios.put(R.id.progress_1, new Ratio(4.0f, 1.0f));
            mRatios.put(R.id.progress_2, new Ratio(3.5f, 1.5f));
            mRatios.put(R.id.progress_3, new Ratio(3.0f, 2.0f));
            mRatios.put(R.id.progress_4, new Ratio(2.5f, 2.5f));
            mRatios.put(R.id.progress_5, new Ratio(2.0f, 3.0f));
            mRatios.put(R.id.progress_6, new Ratio(1.5f, 3.5f));
            mRatios.put(R.id.progress_7, new Ratio(1.0f, 4.0f));

            mRatios.put(R.id.selected_day_image_view, mRatios.get(R.id.progress_4));
        }

        return mRatios;
    }

    /**
     * Stops the {@link android.support.v4.view.ViewPager} from scrolling the root frame
     * while we perform animations on its children
     * </p>
     * This method can sometimes have an issue, not resetting the alpha and visibility to visible.
     * A fix has been applied to this issue in {@link com.github.omadahealth.slidepager.lib.views.SlideView#resetPage(TypedArray)}.
     *
     * @param view     The root view
     * @param position The position the ViewPager is in
     */
    private void lockPage(View view, float position) {
        view.setTranslationX(view.getWidth() * -position);
        if (Math.abs(position) >= 1f) {
            view.setAlpha(0.0F);
            view.setVisibility(View.INVISIBLE);
        } else if (position == 0.0F) {
            view.setAlpha(1.0F);
            view.setVisibility(View.VISIBLE);
        } else {
            view.setAlpha(1.0F - (Math.abs(position) * 2));
            view.setVisibility(View.VISIBLE);
        }
    }

}