实现自定义view(2):仿Android QQ多屏幕显示ListView的效果
转载请注明出处。博客地址:http://blog.csdn.net/mylzc
本文在《仿 UC,墨迹天气左右拖动 多屏幕显示效果》的基础上对代码进行修改,模仿Android QQ主界面的分屏ListView滑动效果。
当进行横向滑动时,会切换屏幕,当纵向滑动时,ListView会滚动。
效果图如下:
代码如下:
FlingGallery.java
- package com.droidful.flinggallery;
- import android.content.Context;
- import android.util.Log;
- import android.view.GestureDetector;
- import android.view.KeyEvent;
- import android.view.MotionEvent;
- import android.view.View;
- 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;
- // 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 FlingGallery extends FrameLayout
- {
- // Constants
- private final int swipe_min_distance = 120;
- private final int swipe_max_off_path = 250;
- private final int swipe_threshold_veloicty = 400;
- // Properties
- private int mViewPaddingWidth = 0;
- private int mAnimationDuration = 250;
- private float mSnapBorderRatio = 0.5f;
- private boolean mIsGalleryCircular = true;
- private int mDetectScrollX = 50;
- // Members
- private int mGalleryWidth = 0;
- private boolean mIsTouched = false;
- private boolean mIsDragging = false;
- private float mCurrentOffset = 0.0f;
- private long mScrollTimestamp = 0;
- private int mFlingDirection = 0;
- private int mCurrentPosition = 0;
- private int mCurrentViewNumber = 0;
- private Context mContext;
- private Adapter mAdapter;
- private FlingGalleryView[] mViews;
- private FlingGalleryAnimation mAnimation;
- private GestureDetector mGestureDetector;
- private FlingGestureDetectorListener mGestureDetectorListener;
- private GestureDetector mInterruptDetector;
- private Interpolator mDecelerateInterpolater;
- public FlingGallery(Context context)
- {
- super(context);
- mContext = context;
- mAdapter = null;
- mViews = new FlingGalleryView[3];
- mViews[0] = new FlingGalleryView(0, this);
- mViews[1] = new FlingGalleryView(1, this);
- mViews[2] = new FlingGalleryView(2, this);
- mAnimation = new FlingGalleryAnimation();
- mGestureDetectorListener = new FlingGestureDetectorListener();
- mGestureDetector = new GestureDetector(mGestureDetectorListener);
- mInterruptDetector = new GestureDetector(new InterruptGestureDetectorListener());
- 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())
- {
- // We need to reload the view immediately to the left to change it to circular view or blank
- mViews[getPrevViewNumber(mCurrentViewNumber)].recycleView(getPrevPosition(mCurrentPosition));
- }
- if (mCurrentPosition == getLastPosition())
- {
- // We need to reload the view immediately to the right to change it to circular view or blank
- mViews[getNextViewNumber(mCurrentViewNumber)].recycleView(getNextPosition(mCurrentPosition));
- }
- }
- }
- public int getGalleryCount()
- {
- return (mAdapter == null) ? 0 : mAdapter.getCount();
- }
- public int getFirstPosition()
- {
- return 0;
- }
- @Override
- public boolean onInterceptTouchEvent (MotionEvent ev) {
- return mInterruptDetector.onTouchEvent(ev);
- }
- @Override
- public boolean onTouchEvent (MotionEvent ev) {
- Log.d("Test", "test" );
- boolean value = onGalleryTouchEvent(ev);
- Log.d("Test", "" + value);
- return true;
- }
- public int getLastPosition()
- {
- return (getGalleryCount() == 0) ? 0 : getGalleryCount() - 1;
- }
- private int getPrevPosition(int relativePosition)
- {
- int prevPosition = relativePosition - 1;
- if (prevPosition < getFirstPosition())
- {
- prevPosition = getFirstPosition() - 1;
- if (mIsGalleryCircular == true)
- {
- prevPosition = getLastPosition();
- }
- }
- return prevPosition;
- }
- private int getNextPosition(int relativePosition)
- {
- int nextPosition = relativePosition + 1;
- if (nextPosition > getLastPosition())
- {
- nextPosition = getLastPosition() + 1;
- if (mIsGalleryCircular == true)
- {
- nextPosition = getFirstPosition();
- }
- }
- return nextPosition;
- }
- private int getPrevViewNumber(int relativeViewNumber)
- {
- return (relativeViewNumber == 0) ? 2 : relativeViewNumber - 1;
- }
- private int getNextViewNumber(int relativeViewNumber)
- {
- return (relativeViewNumber == 2) ? 0 : relativeViewNumber + 1;
- }
- @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;
- 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);
- }
- }
- public void setAdapter(Adapter adapter)
- {
- mAdapter = adapter;
- mCurrentPosition = 0;
- mCurrentViewNumber = 0;
- // Load the initial views from adapter
- mViews[0].recycleView(mCurrentPosition);
- mViews[1].recycleView(getNextPosition(mCurrentPosition));
- mViews[2].recycleView(getPrevPosition(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);
- }
- private int getViewOffset(int viewNumber, int relativeViewNumber)
- {
- // Determine width including configured padding width
- int offsetWidth = mGalleryWidth + mViewPaddingWidth;
- // Position the previous view one measured width to left
- if (viewNumber == getPrevViewNumber(relativeViewNumber))
- {
- return offsetWidth;
- }
- // Position the next view one measured width to the right
- if (viewNumber == getNextViewNumber(relativeViewNumber))
- {
- return offsetWidth * -1;
- }
- return 0;
- }
- void movePrevious()
- {
- // Slide to previous view
- mFlingDirection = 1;
- processGesture();
- }
- void moveNext()
- {
- // Slide to next view
- mFlingDirection = -1;
- processGesture();
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event)
- {
- switch (keyCode)
- {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- movePrevious();
- return true;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- moveNext();
- return true;
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER:
- }
- return super.onKeyDown(keyCode, event);
- }
- public boolean onGalleryTouchEvent(MotionEvent event)
- {
- boolean consumed = mGestureDetector.onTouchEvent(event);
- if (event.getAction() == MotionEvent.ACTION_UP)
- {
- if (mIsTouched || mIsDragging)
- {
- processScrollSnap();
- processGesture();
- }
- }
- return consumed;
- }
- void processGesture()
- {
- int newViewNumber = mCurrentViewNumber;
- int reloadViewNumber = 0;
- int reloadPosition = 0;
- mIsTouched = false;
- mIsDragging = false;
- if (mFlingDirection > 0)
- {
- if (mCurrentPosition > getFirstPosition() || mIsGalleryCircular == true)
- {
- // Determine previous view and outgoing view to recycle
- newViewNumber = getPrevViewNumber(mCurrentViewNumber);
- mCurrentPosition = getPrevPosition(mCurrentPosition);
- reloadViewNumber = getNextViewNumber(mCurrentViewNumber);
- reloadPosition = getPrevPosition(mCurrentPosition);
- }
- }
- if (mFlingDirection < 0)
- {
- if (mCurrentPosition < getLastPosition() || mIsGalleryCircular == true)
- {
- // Determine the next view and outgoing view to recycle
- newViewNumber = getNextViewNumber(mCurrentViewNumber);
- mCurrentPosition = getNextPosition(mCurrentPosition);
- reloadViewNumber = getPrevViewNumber(mCurrentViewNumber);
- reloadPosition = getNextPosition(mCurrentPosition);
- }
- }
- if (newViewNumber != mCurrentViewNumber)
- {
- mCurrentViewNumber = newViewNumber;
- // Reload outgoing view from adapter in new position
- mViews[reloadViewNumber].recycleView(reloadPosition);
- }
- // 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
- float rollEdgeWidth = mGalleryWidth * mSnapBorderRatio;
- int rollOffset = mGalleryWidth - (int) rollEdgeWidth;
- int currentOffset = mViews[mCurrentViewNumber].getCurrentOffset();
- if (currentOffset <= rollOffset * -1)
- {
- // Snap to previous view
- mFlingDirection = 1;
- }
- if (currentOffset >= rollOffset)
- {
- // Snap to next view
- mFlingDirection = -1;
- }
- }
- 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);
- mInvalidLayout.setLayoutParams(new LinearLayout.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- // Internal layout is permanent for duration
- mInternalLayout = new LinearLayout(mContext);
- mInternalLayout.setLayoutParams(new LinearLayout.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- mParentLayout.addView(mInternalLayout);
- }
- public void recycleView(int newPosition)
- {
- if (mExternalView != null)
- {
- mInternalLayout.removeView(mExternalView);
- }
- if (mAdapter != null)
- {
- if (newPosition >= getFirstPosition() && newPosition <= getLastPosition())
- {
- mExternalView = mAdapter.getView(newPosition, mExternalView, mInternalLayout);
- }
- else
- {
- mExternalView = mInvalidLayout;
- }
- }
- if (mExternalView != null)
- {
- mInternalLayout.addView(mExternalView, new LinearLayout.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- }
- }
- public void setOffset(int xOffset, int yOffset, int relativeViewNumber)
- {
- // Scroll the target view relative to its own position relative to currently displayed view
- mInternalLayout.scrollTo(getViewOffset(mViewNumber, relativeViewNumber) + xOffset, yOffset);
- }
- public int getCurrentOffset()
- {
- // Return the current scroll position
- return mInternalLayout.getScrollX();
- }
- public void requestFocus()
- {
- 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;
- }
- 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 = (relativeViewNumber == getPrevViewNumber(mRelativeViewNumber)) ? 1 : -1;
- int animDirection = (mTargetDistance < 0) ? 1 : -1;
- // If animation in same direction
- if (animDirection == newDirection)
- {
- // Ran out of time to animate so snap to the target offset
- mViews[0].setOffset(mTargetOffset, 0, mRelativeViewNumber);
- mViews[1].setOffset(mTargetOffset, 0, mRelativeViewNumber);
- mViews[2].setOffset(mTargetOffset, 0, 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
- mInitialOffset = mViews[mRelativeViewNumber].getCurrentOffset();
- 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 < 3; viewNumber++)
- {
- // Only need to animate the visible views as the other view will always be off-screen
- if ((mTargetDistance > 0 && viewNumber != getNextViewNumber(mRelativeViewNumber)) ||
- (mTargetDistance < 0 && viewNumber != getPrevViewNumber(mRelativeViewNumber)))
- {
- mViews[viewNumber].setOffset(offset, 0, mRelativeViewNumber);
- }
- }
- }
- @Override
- public boolean getTransformation(long currentTime, Transformation outTransformation)
- {
- if (super.getTransformation(currentTime, outTransformation) == false)
- {
- // Perform final adjustment to offsets to cleanup animation
- mViews[0].setOffset(mTargetOffset, 0, mRelativeViewNumber);
- mViews[1].setOffset(mTargetOffset, 0, mRelativeViewNumber);
- mViews[2].setOffset(mTargetOffset, 0, 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;
- }
- }
- private class InterruptGestureDetectorListener extends GestureDetector.SimpleOnGestureListener {
- @Override
- public boolean onDown(MotionEvent e)
- {
- // Stop animation
- mIsTouched = true;
- // Reset fling state
- mFlingDirection = 0;
- return false;
- }
- //返回true由FlingGallery的onTouchEvent(MotionEvent)来处理触摸消息,返回false则先由子view(listview)来处理触摸消息
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
- {
- if (e2.getAction() == MotionEvent.ACTION_MOVE)
- {
- float maxVelocity = mGalleryWidth / (mAnimationDuration / 1000.0f);
- long timestampDelta = System.currentTimeMillis() - mScrollTimestamp;
- float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f);
- float currentScrollDelta = e1.getX() - e2.getX();
- if (currentScrollDelta < maxScrollDelta * -1) currentScrollDelta = maxScrollDelta * -1;
- if (currentScrollDelta > maxScrollDelta) currentScrollDelta = maxScrollDelta;
- if(Math.abs(currentScrollDelta) > mDetectScrollX){//如果当前x方向滚动的距离大于50,则由FlingGallery的onTouchEvent(MotionEvent)来处理触摸消息
- mGestureDetectorListener.setDownEvent(e1);//重新设置mGestureDetectorListener的down消息
- return true;
- }
- }
- return false;//不打断,交给子view来处理触摸消息
- }
- }
- private class FlingGestureDetectorListener extends GestureDetector.SimpleOnGestureListener
- {
- private MotionEvent mDownEvent;
- public void setDownEvent(MotionEvent downEvent) {//复原丢失的Down触摸消息
- mDownEvent = downEvent;
- }
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
- {
- 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;
- float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f);
- float currentScrollDelta = mDownEvent.getX() - e2.getX();
- if (currentScrollDelta < maxScrollDelta * -1) currentScrollDelta = maxScrollDelta * -1;
- if (currentScrollDelta > maxScrollDelta) currentScrollDelta = maxScrollDelta;
- int scrollOffset = Math.round(mCurrentOffset + currentScrollDelta);
- // We can't scroll more than the width of our own frame layout
- if (scrollOffset >= mGalleryWidth) scrollOffset = mGalleryWidth;
- if (scrollOffset <= mGalleryWidth * -1) scrollOffset = mGalleryWidth * -1;
- mViews[0].setOffset(scrollOffset, 0, mCurrentViewNumber);
- mViews[1].setOffset(scrollOffset, 0, mCurrentViewNumber);
- mViews[2].setOffset(scrollOffset, 0, mCurrentViewNumber);
- }
- return false;
- }
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
- {
- if (Math.abs(mDownEvent.getY() - e2.getY()) <= swipe_max_off_path)
- {
- if (e2.getX() - mDownEvent.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty)
- {
- movePrevious();
- }
- if(mDownEvent.getX() - e2.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty)
- {
- moveNext();
- }
- }
- 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
- mFlingDirection = 0;
- return false;
- }
- }
- }
- package com.droidful.flinggallery;
- import android.app.Activity;
- import android.os.Bundle;
- import android.content.Context;
- import android.graphics.Color;
- import android.util.Log;
- import android.view.Gravity;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.View.OnClickListener;
- import android.widget.ArrayAdapter;
- import android.widget.Button;
- import android.widget.CheckBox;
- import android.widget.EditText;
- import android.widget.LinearLayout;
- import android.widget.ListView;
- import android.widget.TableLayout;
- import android.widget.TextView;
- public class FlingGalleryActivity extends Activity
- {
- private final String[] mLabelArray = {"View1", "View2", "View3"};
- private String[] mAStrings = {
- "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
- "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
- "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
- "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
- "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
- "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr"};
- private String[] mBStrings = {"Baby Swiss",
- "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
- "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
- "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
- "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
- "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
- "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
- "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
- "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
- "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
- "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
- "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
- "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
- "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
- "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
- "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
- "Buxton Blue", };
- private String[] mCStrings = {"Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
- "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
- "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
- "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
- "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
- "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
- "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
- "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
- "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
- "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
- "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
- "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
- "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
- "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
- "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
- "Cypress Grove Chevre"};
- private String[][] strings = {mAStrings,mBStrings,mCStrings};
- private FlingGallery mGallery;
- private CheckBox mCheckBox;
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- mGallery = new FlingGallery(this);
- mGallery.setPaddingWidth(5);
- mGallery.setAdapter(new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, mLabelArray)
- {
- @Override
- public View getView(int position, View convertView, ViewGroup parent)
- {
- ListView lv = new ListView(getApplicationContext());
- lv.setAdapter(new ArrayAdapter<String>(getApplicationContext(),
- android.R.layout.simple_list_item_1, strings[position]));
- return lv;//返回position位置的listview
- }
- });
- LinearLayout layout = new LinearLayout(getApplicationContext());
- layout.setOrientation(LinearLayout.VERTICAL);
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.MATCH_PARENT);
- layoutParams.setMargins(10, 10, 10, 10);
- layoutParams.weight = 1.0f;
- layout.addView(mGallery, layoutParams);
- mCheckBox = new CheckBox(getApplicationContext());
- mCheckBox.setText("Gallery is Circular");
- mCheckBox.setPadding(50, 10, 0, 10);
- mCheckBox.setTextSize(30);
- mCheckBox.setChecked(false);
- mGallery.setIsGalleryCircular(mCheckBox.isChecked());
- mCheckBox.setOnClickListener(new OnClickListener()
- {
- @Override
- public void onClick(View view)
- {
- mGallery.setIsGalleryCircular(mCheckBox.isChecked());
- }
- });
- layout.addView(mCheckBox, new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
- setContentView(layout);
- }
- }
代码解析:
这里不详细解析分屏效果的实现,只说明ViewGroup对触摸消息的分发规则。
FlingGallery继承FrameLayout,FrameLayout的父类是ViewGroup,因此FlingGallery是ViewGroup的派生类。
默认规则下,当触摸消息(MotionEvent)到达ViewGroup时,ViewGroup会先把消息发给子View的onTouchEvent(MotionEvent)方法进行处理,如果子View消耗了消息,那么ViewGroup的onTouchEvent(MotionEvent)将不会接收到消息。
这个例子我们重载了ViewGroup的onInterceptTouchEvent (MotionEvent ev)方法,如果方法返回true则表示交由ViewGroup的onTouchEvent(MotionEvent)来处理触摸消息,false则按默认规则交由子view处理。我们在此方法中检测是否横向滚动,如果是横向滚动,则返回true,消息传递给ViewGroup的onTouchEvent(MotionEvent),如果不是横向滑动则有子view处理消息。
希望觉得有用的同学都顶一下,写博客不容易!