package com.example.fancycoverflowdemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Transformation;
import android.widget.Gallery;
import android.widget.SpinnerAdapter;
public class FancyCoverFlow extends Gallery {
public static final int ACTION_DISTANCE_AUTO = Integer.MAX_VALUE;
public static final float SCALEDOWN_GRAVITY_TOP = 0.0f;
public static final float SCALEDOWN_GRAVITY_CENTER = 0.5f;
public static final float SCALEDOWN_GRAVITY_BOTTOM = 1.0f;
private float reflectionRatio = 0.4f;
private int reflectionGap = 20;
private boolean reflectionEnabled = false;
private float unselectedAlpha;
private Camera transformationCamera;
private int maxRotation = 75;
private float unselectedScale;
private float scaleDownGravity = SCALEDOWN_GRAVITY_CENTER;
/**
* Distance in pixels between the transformation effects (alpha, rotation, zoom) are applied.
*/
private int actionDistance;
/**
* Saturation factor (0-1) of items that reach the outer effects distance.
*/
private float unselectedSaturation;
public FancyCoverFlow(Context context) {
super(context);
this.initialize();
}
public FancyCoverFlow(Context context, AttributeSet attrs) {
super(context, attrs);
this.initialize();
this.applyXmlAttributes(attrs);
}
public FancyCoverFlow(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.initialize();
this.applyXmlAttributes(attrs);
}
private void initialize() {
this.transformationCamera = new Camera();
this.setSpacing(0);
}
private void applyXmlAttributes(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FancyCoverFlow);
this.actionDistance = a.getInteger(R.styleable.FancyCoverFlow_actionDistance, ACTION_DISTANCE_AUTO);
this.scaleDownGravity = a.getFloat(R.styleable.FancyCoverFlow_scaleDownGravity, 1.0f);
this.maxRotation = a.getInteger(R.styleable.FancyCoverFlow_maxRotation, 45);
this.unselectedAlpha = a.getFloat(R.styleable.FancyCoverFlow_unselectedAlpha, 0.3f);
this.unselectedSaturation = a.getFloat(R.styleable.FancyCoverFlow_unselectedSaturation, 0.0f);
this.unselectedScale = a.getFloat(R.styleable.FancyCoverFlow_unselectedScale, 0.75f);
}
// =============================================================================
// Getter / Setter
// =============================================================================
public float getReflectionRatio() {
return reflectionRatio;
}
public void setReflectionRatio(float reflectionRatio) {
if (reflectionRatio <= 0 || reflectionRatio > 0.5f) {
throw new IllegalArgumentException("reflectionRatio may only be in the interval (0, 0.5]");
}
this.reflectionRatio = reflectionRatio;
if (this.getAdapter() != null) {
((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
}
}
public int getReflectionGap() {
return reflectionGap;
}
public void setReflectionGap(int reflectionGap) {
this.reflectionGap = reflectionGap;
if (this.getAdapter() != null) {
((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
}
}
public boolean isReflectionEnabled() {
return reflectionEnabled;
}
public void setReflectionEnabled(boolean reflectionEnabled) {
this.reflectionEnabled = reflectionEnabled;
if (this.getAdapter() != null) {
((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
}
}
/**
* Use this to provide a {@link FancyCoverFlowAdapter} to the coverflow. This
* method will throw an {@link ClassCastException} if the passed adapter does not
* subclass {@link FancyCoverFlowAdapter}.
*
* @param adapter
*/
@Override
public void setAdapter(SpinnerAdapter adapter) {
if (!(adapter instanceof FancyCoverFlowAdapter)) {
throw new ClassCastException(FancyCoverFlow.class.getSimpleName() + " only works in conjunction with a " + FancyCoverFlowAdapter.class.getSimpleName());
}
super.setAdapter(adapter);
}
/**
* Returns the maximum rotation that is applied to items left and right of the center of the coverflow.
*
* @return
*/
public int getMaxRotation() {
return maxRotation;
}
/**
* Sets the maximum rotation that is applied to items left and right of the center of the coverflow.
*
* @param maxRotation
*/
public void setMaxRotation(int maxRotation) {
this.maxRotation = maxRotation;
}
/**
* TODO: Write doc
*
* @return
*/
public float getUnselectedAlpha() {
return this.unselectedAlpha;
}
/**
* TODO: Write doc
*
* @return
*/
public float getUnselectedScale() {
return unselectedScale;
}
/**
* TODO: Write doc
*
* @param unselectedScale
*/
public void setUnselectedScale(float unselectedScale) {
this.unselectedScale = unselectedScale;
}
/**
* TODO: Doc
*
* @return
*/
public float getScaleDownGravity() {
return scaleDownGravity;
}
/**
* TODO: Doc
*
* @param scaleDownGravity
*/
public void setScaleDownGravity(float scaleDownGravity) {
this.scaleDownGravity = scaleDownGravity;
}
/**
* TODO: Write doc
*
* @return
*/
public int getActionDistance() {
return actionDistance;
}
/**
* TODO: Write doc
*
* @param actionDistance
*/
public void setActionDistance(int actionDistance) {
this.actionDistance = actionDistance;
}
/**
* TODO: Write doc
*
* @param unselectedAlpha
*/
@Override
public void setUnselectedAlpha(float unselectedAlpha) {
super.setUnselectedAlpha(unselectedAlpha);
this.unselectedAlpha = unselectedAlpha;
}
/**
* TODO: Write doc
*
* @return
*/
public float getUnselectedSaturation() {
return unselectedSaturation;
}
/**
* TODO: Write doc
*
* @param unselectedSaturation
*/
public void setUnselectedSaturation(float unselectedSaturation) {
this.unselectedSaturation = unselectedSaturation;
}
// =============================================================================
// Supertype overrides
// =============================================================================
@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
//获取当前的item
FancyCoverFlowItemWrapper item = (FancyCoverFlowItemWrapper) child;
if (android.os.Build.VERSION.SDK_INT >= 16) {
//刷新item
item.invalidate();
}
//当前控件的宽度
final int coverFlowWidth = this.getWidth();
final int coverFlowCenter = coverFlowWidth / 2;
final int childWidth = item.getWidth();
final int childHeight = item.getHeight();
//每一个item的中心位置
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 / ac