/*
* Copyright (C) 2012 www.amsoft.cn
*
* 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.ab.view.carousel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Transformation;
// TODO: Auto-generated Javadoc
/**
* © 2012 amsoft.cn
* 名称:CarouselImageView.java
* 描述:图片适配
*
* @author 还如一梦中
* @version v1.0
* @date:2013-11-28 上午11:15:11
*/
public class CarouselImageView extends CarouselSpinner implements GestureDetector.OnGestureListener {
// Static private members
/** Tag for a class logging. */
private static final String TAG = CarouselImageView.class.getSimpleName();
/** If logging should be inside class. */
private static final boolean localLOGV = false;
/** Default min quantity of images. */
private static final int MIN_QUANTITY = 3;
/** Default max quantity of images. */
private static final int MAX_QUANTITY = 12;
/** Max theta. */
private static final float MAX_THETA = 15.0f;
/**
* Duration in milliseconds from the start of a scroll during which we're
* unsure whether the user is scrolling or flinging.
*/
private static final int SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT = 250;
// Private members
/** The info for adapter context menu. */
private AdapterContextMenuInfo mContextMenuInfo;
/**
* How long the transition animation should run when a child view changes
* position, measured in milliseconds.
*/
private int mAnimationDuration = 900;
/** Camera to make 3D rotation. */
private Camera mCamera = new Camera();
/**
* Sets mSuppressSelectionChanged = false. This is used to set it to false
* in the future. It will also trigger a selection changed.
*/
private Runnable mDisableSuppressSelectionChangedRunnable = new Runnable() {
public void run() {
mSuppressSelectionChanged = false;
selectionChanged();
}
};
/**
* The position of the item that received the user's down touch.
*/
private int mDownTouchPosition;
/**
* The view of the item that received the user's down touch.
*/
private View mDownTouchView;
/**
* Executes the delta rotations from a fling or scroll movement.
*/
private FlingRotateRunnable mFlingRunnable = new FlingRotateRunnable();
/**
* Helper for detecting touch gestures.
*/
private GestureDetector mGestureDetector;
/** Gravity for the widget. */
private int mGravity;
/**
* If true, this onScroll is the first for this user's drag (remember, a
* drag sends many onScrolls).
*/
private boolean mIsFirstScroll;
/** Set max qantity of images. */
private int mMaxQuantity = MAX_QUANTITY;
/** Set min quantity of images. */
private int mMinQuantity = MIN_QUANTITY;
/**
* If true, we have received the "invoke" (center or enter buttons) key
* down. This is checked before we action on the "invoke" key up, and is
* subsequently cleared.
*/
private boolean mReceivedInvokeKeyDown;
/**
* The currently selected item's child.
*/
private View mSelectedChild;
/**
* Whether to continuously callback on the item selected listener during a
* fling.
*/
private boolean mShouldCallbackDuringFling = true;
/**
* Whether to callback when an item that is not selected is clicked.
*/
private boolean mShouldCallbackOnUnselectedItemClick = true;
/**
* When fling runnable runs, it resets this to false. Any method along the
* path until the end of its run() can set this to true to abort any
* remaining fling. For example, if we've reached either the leftmost or
* rightmost item, we will set this to true.
*/
private boolean mShouldStopFling;
/**
* If true, do not callback to item selected listener.
*/
private boolean mSuppressSelectionChanged;
/** The axe angle. */
private float mTheta = (float)(15.0f*(Math.PI/180.0));
/** If items should be reflected. */
private boolean mUseReflection;
// Constructors
/**
* Instantiates a new carousel image view.
*
* @param context the context
*/
public CarouselImageView(Context context) {
this(context, null);
}
/**
* Instantiates a new carousel image view.
*
* @param context the context
* @param attrs the attrs
*/
public CarouselImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* Instantiates a new carousel image view.
*
* @param context the context
* @param attrs the attrs
* @param defStyle the def style
*/
public CarouselImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// It's needed to make items with greater value of
// z coordinate to be behind items with lesser z-coordinate
setChildrenDrawingOrderEnabled(true);
// Making user gestures available
mGestureDetector = new GestureDetector(this.getContext(), this);
mGestureDetector.setIsLongpressEnabled(true);
// It's needed to apply 3D transforms to items
// before they are drawn
setStaticTransformationsEnabled(true);
// Retrieve settings
mAnimationDuration = 400;
mUseReflection = false;
int selectedItem = 0;
// next time we go through layout with this value
setNextSelectedPositionInt(selectedItem);
}
// View overrides
// These are for use with horizontal scrollbar
/**
* Compute the horizontal extent of the horizontal scrollbar's thumb
* within the horizontal range. This value is used to compute
* the length of the thumb within the scrollbar's track.
*
* @return the int
*/
@Override
protected int computeHorizontalScrollExtent() {
// Only 1 item is considered to be selected
return 1;
}
/**
* Compute the horizontal offset of the horizontal scrollbar's
* thumb within the horizontal range. This value is used to compute
* the position of the thumb within the scrollbar's track.
*
* @return the int
*/
@Override
protected int computeHorizontalScrollOffset() {
// Current scroll position is the same as the selected position
return mSelectedPosition;
}
/**
* Compute the horizontal range that the horizontal scrollbar represents.
*
* @return the int
*/
@Override
protected int computeHorizontalScrollRange() {
// Scroll range is the same as the item count
return mItemCount;
}
/**
* Implemented to handle touch screen motion events.
*
* @param event the event
* @return true, if successful
*/
@Override
pu