/*
* Copyright 2014 Flavio Faria
*
* 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.marshalchen.common.uimodule.kenburnsview;
import android.graphics.RectF;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import java.util.Random;
public class RandomTransitionGenerator implements TransitionGenerator {
/** Default value for the transition duration in milliseconds. */
public static final int DEFAULT_TRANSITION_DURATION = 10000;
/** Minimum rect dimension factor, according to the maximum one. */
private static final float MIN_RECT_FACTOR = 0.75f;
/** Random object used to generate arbitrary rects. */
private final Random mRandom = new Random(System.currentTimeMillis());
/** The duration, in milliseconds, of each transition. */
private long mTransitionDuration;
/** The {@link android.view.animation.Interpolator} to be used to create transitions. */
private Interpolator mTransitionInterpolator;
/** The last generated transition. */
private Transition mLastGenTrans;
/** The bounds of the drawable when the last transition was generated. */
private RectF mLastDrawableBounds;
public RandomTransitionGenerator() {
this(DEFAULT_TRANSITION_DURATION, new AccelerateDecelerateInterpolator());
}
public RandomTransitionGenerator(long transitionDuration, Interpolator transitionInterpolator) {
setTransitionDuration(transitionDuration);
setTransitionInterpolator(transitionInterpolator);
}
@Override
public Transition generateNextTransition(RectF drawableBounds, RectF viewport) {
RectF srcRect;
if (mLastGenTrans == null || !drawableBounds.equals(mLastDrawableBounds)) {
srcRect = generateRandomRect(drawableBounds, viewport);
} else {
/* Sets the destiny rect of the last transition as the source one
if the current drawable has the same dimensions as the one of
the last transition. */
srcRect = mLastGenTrans.getDestinyRect();
}
RectF dstRect = generateRandomRect(drawableBounds, viewport);
mLastGenTrans = new Transition(srcRect, dstRect, mTransitionDuration,
mTransitionInterpolator);
mLastDrawableBounds = drawableBounds;
return mLastGenTrans;
}
/**
* Generates a random rect that can be fully contained within {@code drawableBounds} and
* has the same aspect ratio of {@code viewportRect}. The dimensions of this random rect
* won't be higher than the largest rect with the same aspect ratio of {@code viewportRect}
* that {@code drawableBounds} can contain. They also won't be lower than the dimensions
* of this upper rect limit weighted by {@code MIN_RECT_FACTOR}.
* @param drawableBounds the bounds of the drawable that will be zoomed and panned.
* @param viewportRect the bounds of the view that the drawable will be shown.
* @return an arbitrary generated rect with the same aspect ratio of {@code viewportRect}
* that will be contained within {@code drawableBounds}.
*/
private RectF generateRandomRect(RectF drawableBounds, RectF viewportRect) {
float drawableRatio = MathUtils.getRectRatio(drawableBounds);
float viewportRectRatio = MathUtils.getRectRatio(viewportRect);
RectF maxCrop;
if (drawableRatio > viewportRectRatio) {
float r = (drawableBounds.height() / viewportRect.height()) * viewportRect.width();
float b = drawableBounds.height();
maxCrop = new RectF(0, 0, r, b);
} else {
float r = drawableBounds.width();
float b = (drawableBounds.width() / viewportRect.width()) * viewportRect.height();
maxCrop = new RectF(0, 0, r, b);
}
float randomFloat = MathUtils.truncate(mRandom.nextFloat(), 2);
float factor = MIN_RECT_FACTOR + ((1 - MIN_RECT_FACTOR) * randomFloat);
float width = factor * maxCrop.width();
float height = factor * maxCrop.height();
int widthDiff = (int) (drawableBounds.width() - width);
int heightDiff = (int) (drawableBounds.height() - height);
int left = widthDiff > 0 ? mRandom.nextInt(widthDiff) : 0;
int top = heightDiff > 0 ? mRandom.nextInt(heightDiff) : 0;
return new RectF(left, top, left + width, top + height);
}
/**
* Sets the duration, in milliseconds, for each transition generated.
* @param transitionDuration the transition duration.
*/
public void setTransitionDuration(long transitionDuration) {
mTransitionDuration = transitionDuration;
}
/**
* Sets the {@link android.view.animation.Interpolator} for each transition generated.
* @param interpolator the transition interpolator.
*/
public void setTransitionInterpolator(Interpolator interpolator) {
mTransitionInterpolator = interpolator;
}
}