com.inmobi.nativead.sample.photopages.CustomViewPager.java Source code

Java tutorial

Introduction

Here is the source code for com.inmobi.nativead.sample.photopages.CustomViewPager.java

Source

/*
 * Copyright 2013 David Schreiber
 *           2013 John Paul Nalog
 *
 *    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 com.inmobi.nativead.sample.photopages;

import com.inmobi.nativead.sample.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Transformation;

public class CustomViewPager extends ViewPager {

    static final int ACTION_DISTANCE_AUTO = Integer.MAX_VALUE;
    static final float SCALEDOWN_GRAVITY_TOP = 0.0f;
    static final float SCALEDOWN_GRAVITY_CENTER = 0.5f;
    static final float SCALEDOWN_GRAVITY_BOTTOM = 1.0f;

    private float unselectedAlpha;
    private Camera transformationCamera;
    private int maxRotation = 75;
    private float unselectedScale;
    private float scaleDownGravity = SCALEDOWN_GRAVITY_CENTER;
    private int actionDistance;
    private float unselectedSaturation;

    public CustomViewPager(Context context) {
        super(context);
        this.initialize();
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.initialize();
        this.applyXmlAttributes(attrs);
    }

    private void initialize() {
        this.transformationCamera = new Camera();
        this.setOffscreenPageLimit(5);
        this.setPageMargin(16);
    }

    private void applyXmlAttributes(AttributeSet attrs) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CustomViewPager);

        this.actionDistance = a.getInteger(R.styleable.CustomViewPager_actionDistance, ACTION_DISTANCE_AUTO);
        this.scaleDownGravity = a.getFloat(R.styleable.CustomViewPager_scaleDownGravity, 1.0f);
        this.maxRotation = a.getInteger(R.styleable.CustomViewPager_maxRotation, 45);
        this.unselectedAlpha = a.getFloat(R.styleable.CustomViewPager_unselectedAlpha, 0.3f);
        this.unselectedSaturation = a.getFloat(R.styleable.CustomViewPager_unselectedSaturation, 0.0f);
        this.unselectedScale = a.getFloat(R.styleable.CustomViewPager_unselectedScale, 0.75f);

        a.recycle();
    }

    /**
     * Use this to provide a {@link CustomPagerAdapter} to the coverflow. This method will throw an
     * {@link ClassCastException} if the passed adapter does not subclass {@link CustomPagerAdapter}.
     *
     * @param adapter
     */
    @Override
    public void setAdapter(PagerAdapter adapter) {
        if (!(adapter instanceof CustomPagerAdapter)) {
            throw new ClassCastException(CustomViewPager.class.getSimpleName()
                    + " only works in conjunction with a " + CustomPagerAdapter.class.getSimpleName());
        }

        super.setAdapter(adapter);
    }

    @Override
    protected boolean getChildStaticTransformation(View child, Transformation t) {
        // We can cast here because CustomPagerAdapter only creates wrappers.
        CustomViewPagerItemWrapper item = (CustomViewPagerItemWrapper) child;

        // Since Jelly Bean children won't get invalidated automatically,
        // needs to be added for the smooth coverflow animation
        if (android.os.Build.VERSION.SDK_INT >= 16) {
            item.invalidate();
        }

        final int coverFlowWidth = this.getWidth();
        final int coverFlowCenter = coverFlowWidth / 2;
        final int childWidth = item.getWidth();
        final int childHeight = item.getHeight();
        final int childCenter = item.getLeft() + childWidth / 2;

        // Use coverflow width when its defined as automatic.
        final int actionDistance = (this.actionDistance == ACTION_DISTANCE_AUTO)
                ? (int) ((coverFlowWidth + childWidth) / 2.0f)
                : this.actionDistance;

        // Calculate the abstract amount for all effects.
        final float effectsAmount = Math.min(1.0f,
                Math.max(-1.0f, (1.0f / actionDistance) * (childCenter - coverFlowCenter)));

        // Clear previous transformations and set transformation type (matrix + alpha).
        t.clear();
        t.setTransformationType(Transformation.TYPE_BOTH);

        // Alpha
        if (this.unselectedAlpha != 1) {
            final float alphaAmount = (this.unselectedAlpha - 1) * Math.abs(effectsAmount) + 1;
            t.setAlpha(alphaAmount);
        }

        // Saturation
        if (this.unselectedSaturation != 1) {
            // Pass over saturation to the wrapper.
            final float saturationAmount = (this.unselectedSaturation - 1) * Math.abs(effectsAmount) + 1;
            item.setSaturation(saturationAmount);
        }

        final Matrix imageMatrix = t.getMatrix();

        // Apply rotation.
        if (this.maxRotation != 0) {
            final int rotationAngle = (int) (-effectsAmount * this.maxRotation);
            this.transformationCamera.save();
            this.transformationCamera.rotateY(rotationAngle);
            this.transformationCamera.getMatrix(imageMatrix);
            this.transformationCamera.restore();
        }

        // Zoom.
        if (this.unselectedScale != 1) {
            final float zoomAmount = (this.unselectedScale - 1) * Math.abs(effectsAmount) + 1;
            // Calculate the scale anchor (y anchor can be altered)
            final float translateX = childWidth / 2.0f;
            final float translateY = childHeight * this.scaleDownGravity;
            imageMatrix.preTranslate(-translateX, -translateY);
            imageMatrix.postScale(zoomAmount, zoomAmount);
            imageMatrix.postTranslate(translateX, translateY);
        }

        return true;
    }

    public static class LayoutParams extends ViewPager.LayoutParams {
        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }
    }
}