自定义android循环拖动组件
openkk
13年前
package com.sunny.pager; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationSet; import android.view.animation.ScaleAnimation; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.VideoView; public class ViewpagertestActivity extends Activity { private static Context mContext; private MyFrameLayout mGallery; int[] color = {Color.CYAN, Color.BLUE, Color.GREEN, Color.RED, Color.GRAY, Color.YELLOW, Color.DKGRAY, Color.LTGRAY, Color.MAGENTA}; static String[] str = {"http://www.yoho.cn", "http://www.hibox.com/web/"}; private int count = 9; /** Called when the activity is first created. */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); /** 标题是属于View的,所以窗口所有的修饰部分被隐藏后标题依然有效 */ requestWindowFeature(Window.FEATURE_NO_TITLE); Map<Integer, int[]> mapIndexs = new HashMap<Integer, int[]>(); mapIndexs.put(0, new int[]{0, 1, 2}); mapIndexs.put(1, new int[]{3, 4, 5}); mapIndexs.put(2, new int[]{6, 7, 8}); mGallery = new MyFrameLayout(this, mapIndexs); setContentView(mGallery); mContext = this; // LinearLayout layout = (LinearLayout) findViewById(R.id.main_layout); mGallery.setAdapter(baseAdapter); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT); // layout.addView(mGallery, layoutParams); } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub //requestDisallowInterceptTouchEvent(true); Boolean falg = mGallery.onGalleryTouchEvent(event); return falg; } static class ViewHolder { // TextView tView; LinearLayout layout; TextView tView; ImageView image; VideoView video; } public static Bitmap decodeSampledBitmapFromResource(String iamgePath, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(iamgePath, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(iamgePath, options); } public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { if (width > height) { inSampleSize = Math.round((float) height / (float) reqHeight); } else { inSampleSize = Math.round((float) width / (float) reqWidth); } } return inSampleSize; } BaseAdapter baseAdapter = new BaseAdapter() { ViewHolder holder = new ViewHolder(); @Override public View getView(int position, View convertView, ViewGroup parent) { holder.layout = new LinearLayout(mContext); holder.layout.setOrientation(LinearLayout.VERTICAL); holder.tView = new TextView(mContext); holder.layout.addView(holder.tView); if (position > 5) { holder.tView.setText("第 3" + "屏 第" + (position - 5) + "页"); holder.tView.setTextSize(18); } else if (position > 2) { holder.tView.setText("第 2" + "屏 第" + (position - 2) + "页"); holder.tView.setTextSize(18); } else { holder.tView.setText("第 1" + "屏 第" + (position + 1) + "页"); holder.tView.setTextSize(18); } holder.image = new ImageView(mContext); holder.image.setImageBitmap(decodeSampledBitmapFromResource(Environment.getExternalStorageDirectory() + "/2234567.jpg", 300, 200)); if ((position + 1) % 2 == 0) { LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(300, 200); lp.setMargins(0, 0, 0, 0); holder.layout.addView(holder.image, lp); holder.video = new VideoView(mContext); holder.video.setVideoPath("/mnt/sdcard/123456.mp4"); holder.video.start(); LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(300, 200); lp1.setMargins(50, 220, 0, 0); holder.layout.addView(holder.video, lp1); } else { LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(300, 200); lp.setMargins(0, 0, 0, 0); holder.layout.addView(holder.image, lp); ImageView imageView = new ImageView(mContext); imageView.setBackgroundColor(0xff123456); LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(300, 200); lp1.setMargins(0, 220, 0, 0); /* * imageView.setOnClickListener(new OnClickListener() { * * @Override public void onClick(View v) { // TODO * Auto-generated method stub AnimationSet animation = * getFadeInAnimation(3000, 0, null); Toast.makeText(mContext, * "动画----开始", Toast.LENGTH_SHORT).show(); * holder.image.startAnimation(animation); } }); */ AnimationSet animation = getFadeInAnimation(3000, 100, null); holder.image.startAnimation(animation); imageView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_MOVE) { } if (event.getAction() == MotionEvent.ACTION_DOWN) { AnimationSet animation = getFadeInAnimation(3000, 100, null); holder.image.startAnimation(animation); // Toast.makeText(mContext, "动画----开始", // Toast.LENGTH_SHORT).show(); return false; } return false; } }); holder.layout.addView(imageView, lp1); } holder.layout.setBackgroundColor(color[position]); // holder.layout.setTag(holder); return holder.layout; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return position; } @Override public int getCount() { // TODO Auto-generated method stub return count; } }; public AnimationSet getFadeInAnimation(long durationMillis, long delay, AnimationListener listener) { AlphaAnimation alphaAnim = null; ScaleAnimation scaleAnimation = null; if (delay < 0) delay = 0; if (durationMillis <= 100) durationMillis = 300; AnimationSet animationSet = new AnimationSet(true); alphaAnim = new AlphaAnimation(1.0f, 0.0f); scaleAnimation = new ScaleAnimation(1.0f, 0.1f, 1.0f, 0.1f); alphaAnim.setDuration(durationMillis); scaleAnimation.setDuration(durationMillis); alphaAnim.setStartOffset(delay); scaleAnimation.setStartOffset(delay); animationSet.addAnimation(alphaAnim); animationSet.addAnimation(scaleAnimation); animationSet.setFillAfter(true); if (listener != null) alphaAnim.setAnimationListener(listener); Log.v("animationSet", "Get animationSet: "+animationSet.toString()); return animationSet; } }自定义逐渐基本功能实现,现在公开源码。
其中点击触发动画事件未能解决,ontouch 的down 事件响应,但是动画就是不播放,长安才能在首页播放,希望高手给点建议:
源码:
package com.sunny.pager; import java.util.ArrayList; import java.util.Map; import java.util.Set; import android.R.integer; import android.content.Context; import android.database.DataSetObserver; import android.util.Log; import android.view.GestureDetector; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.animation.Transformation; import android.widget.Adapter; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.Toast; // TODO: // 1. In order to improve performance Cache screen bitmap and use for animation // 2. Establish superfluous memory allocations and delay or replace with reused objects // Probably need to make sure we are not allocating objects (strings, etc.) in loops public class MyFrameLayout extends FrameLayout { // Constants private final int swipe_min_distance = 120; private final int swipe_max_off_path = 250; private final int swipe_threshold_veloicty = 350; // Properties private int mViewPaddingWidth = 0; private int mAnimationDuration = 250; private float mSnapBorderRatio = 0.5f; private boolean mIsGalleryCircular = true; // Members private int mGalleryWidth = 0; private int mGalleryHeight = 0; private boolean mIsTouched = false; private boolean mIsDragging = false; private int[] mCurrentOffset = new int[2]; private long mScrollTimestamp = 0; private int mFlingDirection = 0; private int mCurrentPosition = 0; public int mCurrentViewNumber = 0; private Context mContext; private Adapter mAdapter; private FlingGalleryView[] mViews; private FlingGalleryAnimation mAnimation; private GestureDetector mGestureDetector; private Interpolator mDecelerateInterpolater; Map<Integer, int[]> mapIndexs; private static final int MOVE_UP_DOWN = 0; private static final int MOVE_LEFT_RIGHT = 1; private int MoveStyle = -1; private boolean direction = true; //private int h_viewnumber; //private int v_viewnumber; private ArrayList<Integer> _xViewNumbers=new ArrayList<Integer>(); private ArrayList<Integer> _yViewNumbers=new ArrayList<Integer>(); public MyFrameLayout(Context context, Map<Integer, int[]> mapIndexs) { super(context); this.mapIndexs = mapIndexs; mContext = context; mAdapter = null; mViews = new FlingGalleryView[5]; _xViewNumbers.add(1); _xViewNumbers.add(0); _xViewNumbers.add(2); _yViewNumbers.add(3); _yViewNumbers.add(0); _yViewNumbers.add(4); mViews[0] = new FlingGalleryView(0, this); mViews[1] = new FlingGalleryView(1, this); mViews[2] = new FlingGalleryView(2, this); mViews[3] = new FlingGalleryView(3, this); mViews[4] = new FlingGalleryView(4, this); mAnimation = new FlingGalleryAnimation(); mGestureDetector = new GestureDetector(new FlingGestureDetector()); mDecelerateInterpolater = AnimationUtils.loadInterpolator(mContext, android.R.anim.decelerate_interpolator); } public void setPaddingWidth(int viewPaddingWidth) { mViewPaddingWidth = viewPaddingWidth; } public void setAnimationDuration(int animationDuration) { mAnimationDuration = animationDuration; } public void setSnapBorderRatio(float snapBorderRatio) { mSnapBorderRatio = snapBorderRatio; } public void setIsGalleryCircular(boolean isGalleryCircular) { if (mIsGalleryCircular != isGalleryCircular) { mIsGalleryCircular = isGalleryCircular; if (mCurrentPosition == getFirstPosition_RL()) { // We need to reload the view immediately to the left to change // it to circular view or blank mViews[getPrevViewNumber_RL(mCurrentViewNumber)].recycleView(getPrevPosition_RL(mCurrentPosition)); } if (mCurrentPosition == getLastPosition_RL()) { // We need to reload the view immediately to the right to change // it to circular view or blank mViews[getNextViewNumber_RL(mCurrentViewNumber)].recycleView(getNextPosition_RL(mCurrentPosition)); } if (mCurrentPosition == getFirstPosition_UD()) { mViews[getPrevViewNumber_UD(mCurrentViewNumber)].recycleView(getPrevPosition_UD(mCurrentPosition)); } if (mCurrentPosition == getLastPosition_UD()) { mViews[getNextViewNumber_UD(mCurrentViewNumber)].recycleView(getPrevPosition_UD(mCurrentPosition)); } } } public int getGalleryCount() { return (mAdapter == null) ? 0 : mAdapter.getCount(); } private int[] getXindexAndYindex(int value){ Set<Integer> set=mapIndexs.keySet(); int x_index=-1; for(Integer i : set){ x_index++; int[] temp=mapIndexs.get(i); int y_index=-1; for(int j :temp){ y_index++; if(j==value) return new int[]{x_index,y_index}; } } return new int[]{0,0}; } public int getFirstPosition_RL() { return 0; } public int getLastPosition_RL() { Integer[] vs = mapIndexs.keySet().toArray(new Integer[0]); return vs[vs.length - 1]; } public int getLastPosition_All() { return (getGalleryCount() == 0) ? 0 : getGalleryCount() - 1; } public int getFirstPosition_UD() { int x_index=getXindexAndYindex(mCurrentPosition)[0]; return mapIndexs.get(x_index)[0]; } public int getLastPosition_UD() { int x_index=getXindexAndYindex(mCurrentPosition)[0]; return mapIndexs.get(x_index)[mapIndexs.get(x_index).length - 1]; } private int getPrevPosition_RL(int relativePosition) { int length = mapIndexs.keySet().size(); int lastindex = length - 1; int x_index=getXindexAndYindex(relativePosition)[0]; x_index--; if (x_index < 0) { return mapIndexs.get(lastindex)[0]; } else { return mapIndexs.get(x_index)[0]; } } private int getPrevPosition_UD(int relativePosition) { int x_index=getXindexAndYindex(relativePosition)[0]; int y_index=getXindexAndYindex(relativePosition)[1]; int length = mapIndexs.get(x_index).length; int lastindex = length - 1; y_index--; if (y_index < 0) { return mapIndexs.get(x_index)[lastindex]; } else { return mapIndexs.get(x_index)[y_index]; } } private int getNextPosition_RL(int relativePosition) { int length = mapIndexs.keySet().size(); int x_index=getXindexAndYindex(relativePosition)[0]; int lastindex = length - 1; x_index++; if (x_index > lastindex) { return mapIndexs.get(0)[0]; } else { return mapIndexs.get(x_index)[0]; } } private int getNextPosition_UD(int relativePosition) { int x_index=getXindexAndYindex(relativePosition)[0]; int y_index=getXindexAndYindex(relativePosition)[1]; int length = mapIndexs.get(x_index).length; int lastindex = length - 1; y_index++; if (y_index > lastindex) { return mapIndexs.get(x_index)[0]; } else { return mapIndexs.get(x_index)[y_index]; } } private int getPrevViewNumber_RL(int relativeViewNumber) { int index=_xViewNumbers.indexOf(relativeViewNumber); index=(index == 0) ? 2 : index - 1; return _xViewNumbers.get(index); } private int getNextViewNumber_RL(int relativeViewNumber) { int index=_xViewNumbers.indexOf(relativeViewNumber); index=(index == 2) ? 0: index + 1; return _xViewNumbers.get(index); // return (relativeViewNumber == 2) ? 0 : relativeViewNumber + 1; } private int getPrevViewNumber_UD(int relativeViewNumber) { int index=_yViewNumbers.indexOf(relativeViewNumber); index=(index == 0) ? 2 : index - 1; Log.v("index-------------", index+""); return _yViewNumbers.get(index); } private int getNextViewNumber_UD(int relativeViewNumber) { int index=_yViewNumbers.indexOf(relativeViewNumber); index=(index == 2) ? 0: index + 1; return _yViewNumbers.get(index); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // Calculate our view width mGalleryWidth = (right - left); mGalleryHeight = (bottom - top); if (changed == true) { // Position views at correct starting offsets mViews[0].setOffset(0, 0, mCurrentViewNumber); mViews[1].setOffset(0, 0, mCurrentViewNumber); mViews[2].setOffset(0, 0, mCurrentViewNumber); mViews[3].setOffset(0, 0, mCurrentViewNumber); mViews[4].setOffset(0, 0, mCurrentViewNumber); } } DataSetObserver observer = new DataSetObserver() { public void onChanged() { // mCurrentPosition = 0; // mCurrentViewNumber = 0; // Load the initial views from adapter mViews[0].recycleView(0); mViews[1].recycleView(getNextPosition_RL(0)); mViews[2].recycleView(getPrevPosition_RL(0)); mViews[3].recycleView(getNextPosition_UD(0)); mViews[4].recycleView(getPrevPosition_UD(0)); // Position views at correct starting offsets mViews[0].setOffset(0, 0, 0); mViews[1].setOffset(0, 0, 0); mViews[2].setOffset(0, 0, 0); mViews[3].setOffset(0, 0, 0); mViews[4].setOffset(0, 0, 0); mViews[mCurrentViewNumber].requestFocus(); } }; public void setAdapter(Adapter adapter) { if (null != mAdapter && adapter != null && mAdapter.equals(adapter)) { mAdapter.unregisterDataSetObserver(observer); } mAdapter = adapter; mAdapter.registerDataSetObserver(observer); mCurrentPosition = 0; mCurrentViewNumber = 0; // Load the initial views from adapter mViews[0].recycleView(mCurrentPosition); mViews[1].recycleView(getPrevPosition_RL(mCurrentPosition)); mViews[2].recycleView(getNextPosition_RL(mCurrentPosition)); mViews[3].recycleView(getPrevPosition_UD(mCurrentPosition)); mViews[4].recycleView(getNextPosition_UD(mCurrentPosition)); // Position views at correct starting offsets mViews[0].setOffset(0, 0, mCurrentViewNumber); mViews[1].setOffset(0, 0, mCurrentViewNumber); mViews[2].setOffset(0, 0, mCurrentViewNumber); mViews[3].setOffset(0, 0, mCurrentViewNumber); mViews[4].setOffset(0, 0, mCurrentViewNumber); } private int getViewOffset(int viewNumber, int relativeViewNumber) { int offsetWidth = mGalleryWidth + mViewPaddingWidth; // Position the previous view one measured width to left if (viewNumber == getPrevViewNumber_RL(relativeViewNumber)) { return offsetWidth; } // Position the next view one measured width to the right if (viewNumber == getNextViewNumber_RL(relativeViewNumber)) { return offsetWidth * -1; } int offsetHeight = mGalleryHeight + mViewPaddingWidth; // Position the previous view one measured width to left if (viewNumber == (getPrevViewNumber_UD(relativeViewNumber))) { return offsetHeight; } // Position the next view one measured width to the right int num = getNextViewNumber_UD(relativeViewNumber); if (viewNumber == (num)) { return offsetHeight * -1; } return 0; } public void movePrevious_RL() { // Slide to previous view mFlingDirection = 1; processGesture(); } public void moveNext_RL() { // Slide to next view mFlingDirection = -1; processGesture(); } public void movePrevious_UD() { // Slide to previous view mFlingDirection = 2; processGesture(); } public void moveNext_UD() { // Slide to next view mFlingDirection = -2; processGesture(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT : movePrevious_RL(); MoveStyle = MOVE_LEFT_RIGHT; return true; case KeyEvent.KEYCODE_DPAD_RIGHT : moveNext_RL(); MoveStyle = MOVE_LEFT_RIGHT; return true; case KeyEvent.KEYCODE_DPAD_UP : movePrevious_UD(); MoveStyle = MOVE_UP_DOWN; return true; case KeyEvent.KEYCODE_DPAD_DOWN : moveNext_UD(); MoveStyle = MOVE_UP_DOWN; return true; case KeyEvent.KEYCODE_DPAD_CENTER : case KeyEvent.KEYCODE_ENTER : } return super.onKeyDown(keyCode, event); } public boolean onGalleryTouchEvent(MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { case MotionEvent.ACTION_DOWN : { mLastMotionX = event.getX(); mLastMotionY = event.getY(); break; } case MotionEvent.ACTION_MOVE : { final float x = event.getX();; final float dx = x - mLastMotionX; final float xDiff = Math.abs(dx); final float y = event.getY(); final float yDiff = Math.abs(y - mLastMotionY); if (xDiff > yDiff) { MoveStyle = MOVE_LEFT_RIGHT; } else { if (yDiff > xDiff) { MoveStyle = MOVE_UP_DOWN; } } break; } } boolean consumed=false; if(direction){ consumed = mGestureDetector.onTouchEvent(event); } if (event.getAction() == MotionEvent.ACTION_UP) { //Toast.makeText(mContext, "ACTION_UP", Toast.LENGTH_SHORT).show(); if (mIsTouched || mIsDragging) { direction = false; processScrollSnap(); processGesture(); Toast.makeText(mContext, "processGesture", Toast.LENGTH_SHORT).show(); Log.v("ViewNumbers", "_xViewNumbers :"+ _xViewNumbers.get(0)+ _xViewNumbers.get(1)+ _xViewNumbers.get(2)+ "_yViewNumbers :"+ _yViewNumbers.get(0)+ _yViewNumbers.get(1)+ _yViewNumbers.get(2) ); } } //Toast.makeText(mContext, "consumed : "+consumed, Toast.LENGTH_SHORT).show(); return consumed; } int recyclePositon; int recycleViewNumber; void processGesture() { int newViewNumber = mCurrentViewNumber; int reloadViewNumber = 0; int reloadPosition = 0; int reloadViewNumber_up = 0; int reloadPosition_up = 0; int reloadViewNumber_down = 0; int reloadPosition_down = 0; int reloadViewNumber_r = 0; int reloadPosition_r = 0; int reloadViewNumber_l = 0; int reloadPosition_l = 0; mIsTouched = false; mIsDragging = false; if (mFlingDirection == 1) { if (mCurrentPosition > getFirstPosition_RL() || mIsGalleryCircular == true) { // Determine previous view and outgoing view to recycle newViewNumber = getPrevViewNumber_RL(mCurrentViewNumber); mCurrentPosition = getPrevPosition_RL(mCurrentPosition); recycleViewNumber=mCurrentViewNumber; recyclePositon=getNextPosition_RL(mCurrentPosition); reloadViewNumber = getNextViewNumber_RL(mCurrentViewNumber); reloadPosition = getPrevPosition_RL(mCurrentPosition); reloadPosition_up = getPrevPosition_UD(mCurrentPosition); reloadViewNumber_up = getPrevViewNumber_UD(mCurrentViewNumber); reloadPosition_down = getNextPosition_UD(mCurrentPosition); reloadViewNumber_down = getNextViewNumber_UD(mCurrentViewNumber); int pre=getPrevViewNumber_RL(newViewNumber); int next=getNextViewNumber_RL(newViewNumber); _xViewNumbers.set(0, pre); _xViewNumbers.set(1, newViewNumber); _xViewNumbers.set(2, next); _yViewNumbers.set(1, newViewNumber); } } if (mFlingDirection == 2) { if (mCurrentPosition > getFirstPosition_UD() || mIsGalleryCircular == true) { // Determine previous view and outgoing view to recycle newViewNumber = getPrevViewNumber_UD(mCurrentViewNumber); mCurrentPosition = getPrevPosition_UD(mCurrentPosition); reloadViewNumber = getNextViewNumber_UD(mCurrentViewNumber); reloadPosition = getPrevPosition_UD(mCurrentPosition); reloadPosition_r = getPrevPosition_RL(mCurrentPosition); reloadViewNumber_r = getPrevViewNumber_RL(mCurrentViewNumber); reloadPosition_l = getNextPosition_RL(mCurrentPosition); reloadViewNumber_l = getNextViewNumber_RL(mCurrentViewNumber); int pre=getPrevViewNumber_UD(newViewNumber); int next=getNextViewNumber_UD(newViewNumber); _yViewNumbers.set(0, pre); _yViewNumbers.set(1, newViewNumber); _yViewNumbers.set(2, next); _xViewNumbers.set(1, newViewNumber); } } if (mFlingDirection == -1) { if (mCurrentPosition < getLastPosition_RL() || mIsGalleryCircular == true) { // Determine the next view and outgoing view to recycle newViewNumber = getNextViewNumber_RL(mCurrentViewNumber); mCurrentPosition = getNextPosition_RL(mCurrentPosition); recycleViewNumber=mCurrentViewNumber; recyclePositon=getPrevPosition_RL(mCurrentPosition); reloadViewNumber = getPrevViewNumber_RL(mCurrentViewNumber); reloadPosition = getNextPosition_RL(mCurrentPosition); reloadPosition_up = getPrevPosition_UD(mCurrentPosition); reloadViewNumber_up =getPrevViewNumber_UD(mCurrentViewNumber) ; reloadPosition_down = getNextPosition_UD(mCurrentPosition); reloadViewNumber_down = getNextViewNumber_UD(mCurrentViewNumber); int pre=getPrevViewNumber_RL(newViewNumber); int next=getNextViewNumber_RL(newViewNumber); _xViewNumbers.set(0, pre); _xViewNumbers.set(1, newViewNumber); _xViewNumbers.set(2, next); _yViewNumbers.set(1, newViewNumber); } } if (mFlingDirection == -2) { if (mCurrentPosition < getLastPosition_UD() || mIsGalleryCircular == true) { // Determine the next view and outgoing view to recycle newViewNumber = getNextViewNumber_UD(mCurrentViewNumber); mCurrentPosition = getNextPosition_UD(mCurrentPosition); reloadViewNumber = getPrevViewNumber_UD(mCurrentViewNumber); reloadPosition = getNextPosition_UD(mCurrentPosition); reloadPosition_r = getPrevPosition_RL(mCurrentPosition); reloadViewNumber_r = getPrevViewNumber_RL(mCurrentViewNumber); reloadPosition_l = getNextPosition_RL(mCurrentPosition); reloadViewNumber_l = getNextViewNumber_RL(mCurrentViewNumber); int pre=getPrevViewNumber_UD(newViewNumber); int next=getNextViewNumber_UD(newViewNumber); _yViewNumbers.set(0, pre); _yViewNumbers.set(1, newViewNumber); _yViewNumbers.set(2, next); _xViewNumbers.set(1, newViewNumber); } } if (newViewNumber != mCurrentViewNumber) { mCurrentViewNumber = newViewNumber; // Reload outgoing view from adapter in new position if (MoveStyle == MOVE_LEFT_RIGHT) { mViews[reloadViewNumber].recycleView(reloadPosition); mViews[reloadViewNumber_up].recycleView(reloadPosition_up); mViews[reloadViewNumber_down].recycleView(reloadPosition_down); } else if (MoveStyle == MOVE_UP_DOWN) { mViews[reloadViewNumber].recycleView(reloadPosition); mViews[reloadViewNumber_r].recycleView(reloadPosition_r); mViews[reloadViewNumber_l].recycleView(reloadPosition_l); } } // Ensure input focus on the current view mViews[mCurrentViewNumber].requestFocus(); // Run the slide animations for view transitions mAnimation.prepareAnimation(mCurrentViewNumber); this.startAnimation(mAnimation); // Reset fling state mFlingDirection = 0; } void processScrollSnap() { // Snap to next view if scrolled passed snap position if (MoveStyle == MOVE_LEFT_RIGHT) { float rollEdgeWidth = mGalleryWidth * mSnapBorderRatio; int rollOffset = mGalleryWidth - (int) rollEdgeWidth; int currentOffset = mViews[mCurrentViewNumber].getCurrentOffset()[0]; if (currentOffset <= rollOffset * -1) { // Snap to previous view mFlingDirection = 1; } if (currentOffset >= rollOffset) { // Snap to next view mFlingDirection = -1; } } else if (MoveStyle == MOVE_UP_DOWN) { float rollEdgeHeight = mGalleryHeight * mSnapBorderRatio; int rollOffset_Y = mGalleryHeight - (int) rollEdgeHeight; int currentOffset_Y = mViews[mCurrentViewNumber].getCurrentOffset()[1]; if (currentOffset_Y <= rollOffset_Y * -1) { // Snap to previous view mFlingDirection = 2; } if (currentOffset_Y >= rollOffset_Y) { // Snap to next view mFlingDirection = -2; } } } private class FlingGalleryView { private int mViewNumber; private FrameLayout mParentLayout; private FrameLayout mInvalidLayout = null; private LinearLayout mInternalLayout = null; private View mExternalView = null; public FlingGalleryView(int viewNumber, FrameLayout parentLayout) { mViewNumber = viewNumber; mParentLayout = parentLayout; // Invalid layout is used when outside gallery mInvalidLayout = new FrameLayout(mContext); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); lp.gravity = Gravity.CENTER; mInvalidLayout.setLayoutParams(lp); // Internal layout is permanent for duration mInternalLayout = new LinearLayout(mContext); mInternalLayout.setLayoutParams(lp); mInternalLayout.setPersistentDrawingCache(ViewGroup.PERSISTENT_ALL_CACHES); mParentLayout.addView(mInternalLayout, lp); } public void recycleView(int newPosition) { if (mExternalView != null) { mInternalLayout.removeView(mExternalView); } if (mAdapter != null) { if (newPosition >= 0 && newPosition <= getLastPosition_All()) { mExternalView = mAdapter.getView(newPosition, mExternalView, mInternalLayout); } else { mExternalView = mInvalidLayout; } } if (mExternalView != null) { mInternalLayout.addView(mExternalView, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); } } public void setOffset(int xOffset, int yOffset, int relativeViewNumber) { // Scroll the target view relative to its own position relative to // currently displayed view int distance = getViewOffset(mViewNumber, relativeViewNumber); int x=mGalleryWidth + mViewPaddingWidth; int y=mGalleryHeight + mViewPaddingWidth; if(Math.abs(distance)==x){ mInternalLayout.scrollTo(distance + xOffset, yOffset); }else if(Math.abs(distance)==y){ mInternalLayout.scrollTo(xOffset, distance + yOffset); }else if(Math.abs(distance)==0){ mInternalLayout.scrollTo(xOffset, yOffset); } Log.v("Position", "mViewNumber: " + mViewNumber + " mCurrentViewNumber: " + mCurrentViewNumber+ " distance: " + distance); } public int[] getCurrentOffset() { // Return the current scroll position return new int[]{mInternalLayout.getScrollX(), mInternalLayout.getScrollY()}; } public void requestFocus() { mInternalLayout.setFocusable(true); mInternalLayout.setFocusableInTouchMode(true); mInternalLayout.requestFocus(); } } private class FlingGalleryAnimation extends Animation { private boolean mIsAnimationInProgres; private int mRelativeViewNumber; private int mInitialOffset; private int mTargetOffset; private int mTargetDistance; public FlingGalleryAnimation() { mIsAnimationInProgres = false; mRelativeViewNumber = 0; mInitialOffset = 0; mTargetOffset = 0; mTargetDistance = 0; } @Override public boolean getFillAfter() { // TODO Auto-generated method stub mViews[recycleViewNumber].recycleView(recyclePositon); direction = true; boolean falg=super.getFillAfter(); return falg; } public void prepareAnimation(int relativeViewNumber) { // If we are animating relative to a new view if (mRelativeViewNumber != relativeViewNumber) { if (mIsAnimationInProgres == true) { // We only have three views so if requested again to animate // in same direction we must snap int newDirection=0; int animDirection = (mTargetDistance < 0) ? 1 : -1; if (MoveStyle == MOVE_LEFT_RIGHT) { newDirection = (relativeViewNumber == getPrevViewNumber_RL(mRelativeViewNumber)) ? 1 : -1; // If animation in same direction if (animDirection == newDirection) { // Ran out of time to animate so snap to the target // offset mViews[_xViewNumbers.get(0)].setOffset(mTargetOffset, 0, mRelativeViewNumber); mViews[_xViewNumbers.get(1)].setOffset(mTargetOffset, 0, mRelativeViewNumber); mViews[_xViewNumbers.get(2)].setOffset(mTargetOffset, 0, mRelativeViewNumber); } } else if (MoveStyle == MOVE_UP_DOWN) { newDirection = (relativeViewNumber == getPrevViewNumber_UD(mRelativeViewNumber)) ? 1 : -1; if (animDirection == newDirection) { // Ran out of time to animate so snap to the target // offset mViews[_yViewNumbers.get(0)].setOffset(0, mTargetOffset, mRelativeViewNumber); mViews[_yViewNumbers.get(1)].setOffset(0, mTargetOffset, mRelativeViewNumber); mViews[_yViewNumbers.get(2)].setOffset(0, mTargetOffset, mRelativeViewNumber); } } } // Set relative view number for animation mRelativeViewNumber = relativeViewNumber; } // Note: In this implementation the targetOffset will always be zero // as we are centering the view; but we include the calculations of // targetOffset and targetDistance for use in future implementations if (MoveStyle == MOVE_LEFT_RIGHT) { mInitialOffset = mViews[mRelativeViewNumber].getCurrentOffset()[0]; } else if (MoveStyle == MOVE_UP_DOWN) { mInitialOffset = mViews[mRelativeViewNumber].getCurrentOffset()[1]; } mTargetOffset = getViewOffset(mRelativeViewNumber, mRelativeViewNumber); mTargetDistance = mTargetOffset - mInitialOffset; // Configure base animation properties this.setDuration(mAnimationDuration); this.setInterpolator(mDecelerateInterpolater); // Start/continued animation mIsAnimationInProgres = true; } @Override protected void applyTransformation(float interpolatedTime, Transformation transformation) { // Ensure interpolatedTime does not over-shoot then calculate new // offset interpolatedTime = (interpolatedTime > 1.0f) ? 1.0f : interpolatedTime; int offset = mInitialOffset + (int) (mTargetDistance * interpolatedTime); for (int viewNumber = 0; viewNumber < 5; viewNumber++) { // Only need to animate the visible views as the other view will // always be off-screen if (MoveStyle == MOVE_LEFT_RIGHT) { if ((mTargetDistance > 0 && viewNumber != getNextViewNumber_RL(mRelativeViewNumber)) || (mTargetDistance < 0 && viewNumber != getPrevViewNumber_RL(mRelativeViewNumber))) { mViews[viewNumber].setOffset(offset, 0, mRelativeViewNumber); } } else if (MoveStyle == MOVE_UP_DOWN ) { if ((mTargetDistance > 0 && viewNumber != getNextViewNumber_UD(mRelativeViewNumber)) || (mTargetDistance < 0 && viewNumber != getPrevViewNumber_UD(mRelativeViewNumber))) { mViews[viewNumber].setOffset(0, offset, mRelativeViewNumber); } } } } @Override public boolean getTransformation(long currentTime, Transformation outTransformation) { if (super.getTransformation(currentTime, outTransformation) == false) { // Perform final adjustment to offsets to cleanup animation Log.v("mTargetOffset", "mTargetOffset: " + mTargetOffset); if (MoveStyle == MOVE_LEFT_RIGHT) { mViews[_xViewNumbers.get(0)].setOffset(mTargetOffset, 0, mRelativeViewNumber); mViews[_xViewNumbers.get(1)].setOffset(mTargetOffset, 0, mRelativeViewNumber); mViews[_xViewNumbers.get(2)].setOffset(mTargetOffset, 0, mRelativeViewNumber); } else if (MoveStyle == MOVE_UP_DOWN) { mViews[_yViewNumbers.get(0)].setOffset(0, mTargetOffset, mRelativeViewNumber); mViews[_yViewNumbers.get(1)].setOffset(0, mTargetOffset, mRelativeViewNumber); mViews[_yViewNumbers.get(2)].setOffset(0, mTargetOffset, mRelativeViewNumber); } // Reached the animation target mIsAnimationInProgres = false; return false; } // Cancel if the screen touched if (mIsTouched || mIsDragging) { // Note that at this point we still consider ourselves to be // animating // because we have not yet reached the target offset; its just // that the // user has temporarily interrupted the animation with a touch // gesture return false; } return true; } } float mLastMotionX = 0; float mLastMotionY = 0; // int firstx = 0; private class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { // firstx = (int) e.getX(); // Stop animation //mIsTouched = true; // Reset fling state mFlingDirection = 0; return true; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // int scrollOffset = 0; if (e2.getAction() == MotionEvent.ACTION_MOVE) { if (mIsDragging == false) { // Stop animation mIsTouched = true; // Reconfigure scroll mIsDragging = true; mFlingDirection = 0; mScrollTimestamp = System.currentTimeMillis(); mCurrentOffset = mViews[mCurrentViewNumber].getCurrentOffset(); } float maxVelocity = mGalleryWidth / (mAnimationDuration / 1000.0f); long timestampDelta = System.currentTimeMillis() - mScrollTimestamp; if (MoveStyle == MOVE_LEFT_RIGHT) { float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f); float currentScrollDelta = e1.getRawX() - e2.getRawX(); if (currentScrollDelta < maxScrollDelta * -1) currentScrollDelta = maxScrollDelta * -1; if (currentScrollDelta > maxScrollDelta) currentScrollDelta = maxScrollDelta; int scrollOffset = Math.round(mCurrentOffset[0] + currentScrollDelta); // We can't scroll more than the width of our own // framelayout if (scrollOffset >= mGalleryWidth) scrollOffset = mGalleryWidth; if (scrollOffset <= mGalleryWidth * -1) scrollOffset = mGalleryWidth * -1; mViews[_xViewNumbers.get(0)].setOffset(scrollOffset, 0, mCurrentViewNumber); mViews[_xViewNumbers.get(1)].setOffset(scrollOffset, 0, mCurrentViewNumber); mViews[_xViewNumbers.get(2)].setOffset(scrollOffset, 0, mCurrentViewNumber); // h_viewnumber=mCurrentViewNumber; } if (MoveStyle == MOVE_UP_DOWN) { float maxVelocity_Y = mGalleryHeight / (mAnimationDuration / 1000.0f); float maxScrollDelta_Y = maxVelocity_Y * (timestampDelta / 1000.0f); float currentScrollDelta_Y = e1.getRawY() - e2.getRawY(); if (currentScrollDelta_Y < maxScrollDelta_Y * -1) currentScrollDelta_Y = maxScrollDelta_Y * -1; if (currentScrollDelta_Y > maxScrollDelta_Y) currentScrollDelta_Y = maxScrollDelta_Y; int scrollOffset_Y = Math.round(mCurrentOffset[1] + currentScrollDelta_Y); if (scrollOffset_Y >= mGalleryHeight) scrollOffset_Y = mGalleryHeight; if (scrollOffset_Y <= mGalleryHeight * -1) scrollOffset_Y = mGalleryHeight * -1; mViews[_yViewNumbers.get(0)].setOffset(0, scrollOffset_Y, mCurrentViewNumber); mViews[_yViewNumbers.get(1)].setOffset(0, scrollOffset_Y, mCurrentViewNumber); mViews[_yViewNumbers.get(2)].setOffset(0, scrollOffset_Y, mCurrentViewNumber); } } return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (Math.abs(e1.getY() - e2.getY()) <= swipe_max_off_path) { if (e2.getX() - e1.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty) { // movePrevious_RL(); } if (e1.getX() - e2.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty) { // moveNext_RL(); } if (e2.getY() - e1.getY() > swipe_min_distance && Math.abs(velocityY) > swipe_threshold_veloicty) { // movePrevious_UD(); } if (e1.getY() - e2.getY() > swipe_min_distance && Math.abs(velocityY) > swipe_threshold_veloicty) { // moveNext_UD(); } } return false; } @Override public void onLongPress(MotionEvent e) { // Finalise scrolling mFlingDirection = 0; processGesture(); } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { // Reset fling state return false; } } }