Android实现多页左右滑动效果,支持子view动态创建和cache

要实现多页滑动效果,主要是需要处理onTouchEventonInterceptTouchEvent,要处理好touch事件的子控件和父控件的传递问题。

滚动控制可以利用androidScroller来实现。

 

这里提供两种做法:

1、自定义MFlipper控件,从ViewGroup继承,利用Scroller实现滚动,重点是onTouchEventonInterceptTouchEvent的重写,

要注意什么时候该返回true,什么时候false。否则会导致界面滑动和界面内按钮点击事件相冲突。

由于采用了ViewGroup来管理子view,只适合于页面数较少而且较固定的情况,因为viewgroup需要一开始就调用addView,把所有view都加进去并layout

太多页面会有内存问题。如果是页面很多,而且随时动态增长的话,就需要考虑对viewcache和动态创建,动态layout,具体做法参考下面的方法二;

 

2、从AdapterView继承,参考Android自带ListView的实现,实现子view动态创建和cache,滑动效果等。

源码如下:

 

    1. import android.content.Context;  
    2.   
    3. import android.util.AttributeSet;  
    4.   
    5. import android.util.Log;  
    6.   
    7. import android.util.SparseArray;  
    8.   
    9. import android.view.MotionEvent;  
    10.   
    11. import android.view.VelocityTracker;  
    12.   
    13. import android.view.View;  
    14.   
    15. import android.view.ViewConfiguration;  
    16.   
    17. import android.view.ViewGroup;  
    18.   
    19. import android.widget.AdapterView;  
    20.   
    21. import android.widget.BaseAdapter;  
    22.   
    23. import android.widget.Gallery;  
    24.   
    25. import android.widget.Scroller;  
    26.   
    27. /** 
    28.  
    29.  * 自定义一个横向滚动的AdapterView,类似与全屏的Gallery,但是一次只滚动一屏,而且每一屏支持子view的点击处理 
    30.  
    31.  * @author weibinke 
    32.  
    33.  * 
    34.  
    35.  */  
    36.   
    37. public class MultiPageSwitcher extends AdapterView<BaseAdapter> {  
    38.   
    39. private BaseAdapter mAdapter = null;  
    40.   
    41. private Scroller mScroller;  
    42.   
    43. private int mTouchSlop;  
    44.   
    45. private float mTouchStartX;  
    46.   
    47. private float mLastMotionX;  
    48.   
    49. private final static String TAG = "MultiPageSwitcher";  
    50.   
    51. private int mLastScrolledOffset = 0;                  
    52.   
    53. /** User is not touching the list */  
    54.   
    55.     private static final int TOUCH_STATE_RESTING = 0;  
    56.   
    57.     /** User is scrolling the list */  
    58.   
    59. private static final int TOUCH_STATE_SCROLL = 2;  
    60.   
    61. private int mTouchState = TOUCH_STATE_RESTING;  
    62.   
    63. private int mHeightMeasureSpec;  
    64.   
    65. private int mWidthMeasureSpec;  
    66.   
    67. private int mSelectedPosition;  
    68.   
    69. private int mFirstPosition;                                //第一个可见view的position  
    70.   
    71. private int mCurrentSelectedPosition;  
    72.   
    73. private VelocityTracker mVelocityTracker;  
    74.   
    75. private static final int SNAP_VELOCITY = 600;  
    76.   
    77. protected RecycleBin mRecycler = new RecycleBin();  
    78.   
    79. private OnPostionChangeListener mOnPostionChangeListener = null;  
    80.   
    81. public MultiPageSwitcher(Context context, AttributeSet attrs) {  
    82.   
    83. super(context, attrs);  
    84.   
    85. mScroller = new Scroller(context);  
    86.   
    87. mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();  
    88.   
    89. }  
    90.   
    91. @Override  
    92.   
    93. protected void onLayout(boolean changed, int left, int top, int right,  
    94.   
    95. int bottom) {  
    96.   
    97. // TODO Auto-generated method stub  
    98.   
    99. MLog.d("MultiPageSwitcher.onlayout start");  
    100.   
    101. super.onLayout(changed, left, top, right, bottom);  
    102.   
    103. if (mAdapter == null) {  
    104.   
    105. return ;  
    106.   
    107. }  
    108.   
    109. recycleAllViews();  
    110.   
    111. detachAllViewsFromParent();  
    112.   
    113. mRecycler.clear();  
    114.   
    115. fillAllViews();  
    116.   
    117. MLog.d("MultiPageSwitcher.onlayout end");  
    118.   
    119. }  
    120.   
    121. /** 
    122.  
    123.  * 从当前可见的view向左边填充 
    124.  
    125.  */  
    126.   
    127. private void fillToGalleryLeft() {  
    128.   
    129.         int itemSpacing = 0;  
    130.   
    131.         int galleryLeft = 0;  
    132.   
    133.         // Set state for initial iteration  
    134.   
    135.         View prevIterationView = getChildAt(0);  
    136.   
    137.         int curPosition;  
    138.   
    139.         int curRightEdge;  
    140.   
    141.         if (prevIterationView != null) {  
    142.             curPosition = mFirstPosition - 1;  
    143.             curRightEdge = prevIterationView.getLeft() - itemSpacing;  
    144.         } else {  
    145.             // No children available!  
    146.             curPosition = 0;  
    147.             curRightEdge = getRight() - getLeft();  
    148.         }  
    149.   
    150.         while (curRightEdge > galleryLeft && curPosition >= 0) {  
    151.   
    152.             prevIterationView = makeAndAddView(curPosition, curPosition - mSelectedPosition,  
    153.   
    154.                     curRightEdge, false);  
    155.   
    156.             // Remember some state  
    157.   
    158.             mFirstPosition = curPosition;  
    159.   
    160.             // Set state for next iteration  
    161.   
    162.             curRightEdge = prevIterationView.getLeft() - itemSpacing;  
    163.   
    164.             curPosition--;  
    165.   
    166.         }  
    167.   
    168.     }  
    169.   
    170.     private void fillToGalleryRight() {  
    171.   
    172.         int itemSpacing = 0;  
    173.   
    174.         int galleryRight = getRight() - getLeft();  
    175.   
    176.         int numChildren = getChildCount();  
    177.   
    178.         int numItems = mAdapter.getCount();  
    179.   
    180.         // Set state for initial iteration  
    181.   
    182.         View prevIterationView = getChildAt(numChildren - 1);  
    183.   
    184.         int curPosition;  
    185.   
    186.         int curLeftEdge;  
    187.   
    188.         if (prevIterationView != null) {  
    189.   
    190.             curPosition = mFirstPosition + numChildren;  
    191.   
    192.             curLeftEdge = prevIterationView.getRight() + itemSpacing;  
    193.   
    194.         } else {  
    195.   
    196.             mFirstPosition = curPosition = numItems - 1;  
    197.   
    198.             curLeftEdge = 0;  
    199.   
    200.         }  
    201.   
    202.         while (curLeftEdge < galleryRight && curPosition < numItems) {  
    203.   
    204.             prevIterationView = makeAndAddView(curPosition, curPosition - mSelectedPosition,  
    205.   
    206.                     curLeftEdge, true);  
    207.   
    208.             // Set state for next iteration  
    209.   
    210.             curLeftEdge = prevIterationView.getRight() + itemSpacing;  
    211.   
    212.             curPosition++;  
    213.   
    214.         }  
    215.   
    216.     }  
    217.   
    218. /** 
    219.  
    220.  *填充view 
    221.  
    222.  */  
    223.   
    224. private void fillAllViews(){  
    225.   
    226. //先创建第一个view,使其居中显示  
    227.   
    228. if (mSelectedPosition >= mAdapter.getCount()&& mSelectedPosition > 0) {  
    229.   
    230. //处理被记录被删除导致当前选中位置超出记录数的情况  
    231.   
    232. mSelectedPosition = mAdapter.getCount() - 1;  
    233.   
    234. if(mOnPostionChangeListener != null){  
    235.   
    236. mCurrentSelectedPosition = mSelectedPosition;  
    237.   
    238. mOnPostionChangeListener.onPostionChange(this, mCurrentSelectedPosition);  
    239.   
    240. }  
    241.   
    242. }  
    243.   
    244.    
    245.   
    246. mFirstPosition = mSelectedPosition;  
    247.   
    248. mCurrentSelectedPosition = mSelectedPosition;  
    249.   
    250.    
    251.   
    252. View child = makeAndAddView(mSelectedPosition, 00true);  
    253.   
    254. int offset = getWidth() / 2 - (child.getLeft() + child.getWidth() / 2);  
    255.   
    256. child.offsetLeftAndRight(offset);  
    257.   
    258. fillToGalleryLeft();  
    259.   
    260. fillToGalleryRight();  
    261. }  
    262.   
    263. /** 
    264.  
    265.      * Obtain a view, either by pulling an existing view from the recycler or by 
    266.  
    267.      * getting a new one from the adapter. If we are animating, make sure there 
    268.  
    269.      * is enough information in the view's layout parameters to animate from the 
    270.  
    271.      * old to new positions. 
    272.  
    273.      * 
    274.  
    275.      * @param position Position in the gallery for the view to obtain 
    276.  
    277.      * @param offset Offset from the selected position 
    278.  
    279.      * @param x X-coordintate indicating where this view should be placed. This 
    280.  
    281.      *        will either be the left or right edge of the view, depending on 
    282.  
    283.      *        the fromLeft paramter 
    284.  
    285.      * @param fromLeft Are we posiitoning views based on the left edge? (i.e., 
    286.  
    287.      *        building from left to right)? 
    288.  
    289.      * @return A view that has been added to the gallery 
    290.  
    291.      */  
    292.   
    293.     private View makeAndAddView(int position, int offset, int x,  
    294.   
    295.             boolean fromLeft) {  
    296.   
    297.         View child;  
    298.   
    299.         //ask the adapter for a view  
    300.   
    301.         child = mAdapter.getView(position, nullthis);  
    302.   
    303.         // Position the view  
    304.   
    305.         setUpChild(child, offset, x, fromLeft);  
    306.   
    307.         return child;  
    308.   
    309.     }  
    310.   
    311.     @Override  
    312.   
    313.     protected ViewGroup.LayoutParams generateDefaultLayoutParams() {  
    314.   
    315.         /* 
    316.  
    317.          * Gallery expects Gallery.LayoutParams. 
    318.  
    319.          */  
    320.   
    321.         return new Gallery.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,  
    322.   
    323.                 ViewGroup.LayoutParams.WRAP_CONTENT);  
    324.   
    325.     }  
    326.   
    327.     /** 
    328.  
    329.      * Helper for makeAndAddView to set the position of a view and fill out its 
    330.  
    331.      * layout paramters. 
    332.  
    333.      * 
    334.  
    335.      * @param child The view to position 
    336.  
    337.      * @param offset Offset from the selected position 
    338.  
    339.      * @param x X-coordintate indicating where this view should be placed. This 
    340.  
    341.      *        will either be the left or right edge of the view, depending on 
    342.  
    343.      *        the fromLeft paramter 
    344.  
    345.      * @param fromLeft Are we posiitoning views based on the left edge? (i.e., 
    346.  
    347.      *        building from left to right)? 
    348.  
    349.      */  
    350.   
    351.     private void setUpChild(View child, int offset, int x, boolean fromLeft) {  
    352.   
    353.         // Respect layout params that are already in the view. Otherwise  
    354.   
    355.         // make some up...  
    356.   
    357.         Gallery.LayoutParams lp = (Gallery.LayoutParams)  
    358.   
    359.             child.getLayoutParams();  
    360.   
    361.         if (lp == null) {  
    362.   
    363.             lp = (Gallery.LayoutParams) generateDefaultLayoutParams();  
    364.   
    365.         }  
    366.   
    367.         addViewInLayout(child, fromLeft ? -1 : 0, lp);  
    368.   
    369.         child.setSelected(offset == 0);  
    370.   
    371.         // Get measure specs  
    372.   
    373.         int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,  
    374.   
    375.                 0, lp.height);  
    376.   
    377.         int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,  
    378.   
    379.                 0, lp.width);  
    380.   
    381.         // Measure child  
    382.   
    383.         child.measure(childWidthSpec, childHeightSpec);  
    384.   
    385.         int childLeft;  
    386.   
    387.         int childRight;  
    388.   
    389.         // Position vertically based on gravity setting  
    390.   
    391.         int childTop = 0;  
    392.   
    393.         int childBottom = childTop + child.getMeasuredHeight();  
    394.   
    395.         int width = child.getMeasuredWidth();  
    396.   
    397.         if (fromLeft) {  
    398.   
    399.             childLeft = x;  
    400.   
    401.             childRight = childLeft + width;  
    402.   
    403.         } else {  
    404.   
    405.             childLeft = x - width;  
    406.   
    407.             childRight = x;  
    408.   
    409.         }  
    410.   
    411.         child.layout(childLeft, childTop, childRight, childBottom);  
    412.   
    413.     }  
    414.   
    415.     @Override  
    416.   
    417.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
    418.   
    419.             // TODO Auto-generated method stub  
    420.   
    421.             super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
    422.   
    423.             mWidthMeasureSpec = widthMeasureSpec;  
    424.   
    425.             mHeightMeasureSpec = heightMeasureSpec;  
    426.   
    427.     }  
    428.   
    429.     @Override  
    430.   
    431.     public int getCount() {  
    432.   
    433.             // TODO Auto-generated method stub  
    434.   
    435.             return mAdapter.getCount();  
    436.   
    437.     }  
    438.   
    439. @Override  
    440.   
    441. public BaseAdapter getAdapter() {  
    442.   
    443. // TODO Auto-generated method stub  
    444.   
    445. return mAdapter;  
    446.   
    447. }  
    448.   
    449.    
    450.   
    451. @Override  
    452.   
    453. public void setAdapter(BaseAdapter adapter) {  
    454.   
    455. // TODO Auto-generated method stub  
    456.   
    457. mAdapter = adapter;  
    458.   
    459. removeAllViewsInLayout();  
    460.   
    461. requestLayout();  
    462.   
    463. }  
    464.   
    465. @Override  
    466.   
    467. public View getSelectedView() {  
    468.   
    469. // TODO Auto-generated method stub  
    470.   
    471. return null;  
    472.   
    473. }  
    474.   
    475.    
    476.   
    477. @Override  
    478.   
    479. public void setSelection(int position) {  
    480.   
    481. // TODO Auto-generated method stub  
    482.   
    483. }  
    484.   
    485. @Override  
    486.   
    487. public boolean onInterceptTouchEvent(MotionEvent event) {  
    488.   
    489. if (!mScroller.isFinished()) {  
    490.   
    491. return true;  
    492.   
    493. }  
    494.   
    495. final int action = event.getAction();  
    496.   
    497. MLog.d("onInterceptTouchEvent action = "+event.getAction());  
    498.   
    499. if (MotionEvent.ACTION_DOWN == action) {  
    500.   
    501. startTouch(event);  
    502.   
    503. return false;  
    504.   
    505. }else if (MotionEvent.ACTION_MOVE == action) {  
    506.   
    507. return startScrollIfNeeded(event);  
    508.   
    509. }else if (MotionEvent.ACTION_UP == action || MotionEvent.ACTION_CANCEL == action) {  
    510.   
    511. mTouchState = TOUCH_STATE_RESTING;  
    512.   
    513. return false;  
    514.   
    515. }  
    516.   
    517. return false;  
    518.   
    519. }  
    520.   
    521. @Override  
    522.   
    523. public boolean onTouchEvent(MotionEvent event) {  
    524.   
    525. if (!mScroller.isFinished()) {  
    526.   
    527. return true;  
    528.   
    529. }  
    530.   
    531. if (mVelocityTracker == null) {  
    532.   
    533. mVelocityTracker = VelocityTracker.obtain();  
    534.   
    535. }  
    536.   
    537. mVelocityTracker.addMovement(event);  
    538.   
    539. MLog.d("onTouchEvent action = "+event.getAction());  
    540.   
    541. final int action = event.getAction();  
    542.   
    543. final float x = event.getX();  
    544.   
    545. if (MotionEvent.ACTION_DOWN == action) {  
    546.   
    547. startTouch(event);  
    548.   
    549. }else if (MotionEvent.ACTION_MOVE == action) {  
    550.   
    551. if (mTouchState == TOUCH_STATE_RESTING) {  
    552.   
    553. startScrollIfNeeded(event);  
    554.   
    555. }else if (mTouchState == TOUCH_STATE_SCROLL) {  
    556.   
    557. int deltaX = (int)(x - mLastMotionX);  
    558.   
    559. mLastMotionX = x;  
    560.   
    561. scrollDeltaX(deltaX);  
    562.   
    563. }  
    564.   
    565. }else if (MotionEvent.ACTION_UP == action || MotionEvent.ACTION_CANCEL == action) {  
    566.   
    567. if (mTouchState == TOUCH_STATE_SCROLL) {  
    568.   
    569. onUp(event);  
    570.   
    571. }  
    572.   
    573. }  
    574.   
    575. return true;  
    576.   
    577. }  
    578.   
    579. private void scrollDeltaX(int deltaX){  
    580.   
    581. //先把现有的view坐标移动  
    582.   
    583. for (int i = 0; i < getChildCount(); i++) {  
    584.   
    585. getChildAt(i).offsetLeftAndRight(deltaX);  
    586.   
    587. }  
    588.   
    589. boolean toLeft = (deltaX < 0);  
    590.   
    591. detachOffScreenChildren(toLeft);  
    592.   
    593. if (deltaX < 0) {  
    594.   
    595. //sroll to right  
    596.   
    597. fillToGalleryRight();  
    598.   
    599. }else {  
    600.   
    601. fillToGalleryLeft();  
    602.   
    603. }  
    604.   
    605. invalidate();  
    606.   
    607. int position = calculteCenterItem() + mFirstPosition;  
    608.   
    609. if (mCurrentSelectedPosition != position) {  
    610.   
    611. mCurrentSelectedPosition = position;  
    612.   
    613. if (mOnPostionChangeListener != null) {  
    614.   
    615. mOnPostionChangeListener.onPostionChange(this, mCurrentSelectedPosition);  
    616.   
    617. }  
    618.   
    619. }  
    620.   
    621. }  
    622.   
    623. private void onUp(MotionEvent event){  
    624.   
    625. final VelocityTracker velocityTracker = mVelocityTracker;    
    626.   
    627. velocityTracker.computeCurrentVelocity(1000);    
    628.   
    629. int velocityX = (int) velocityTracker.getXVelocity();    
    630.   
    631. MLog.d( "onUp velocityX:"+velocityX);  
    632.   
    633. if (velocityX < -SNAP_VELOCITY && mSelectedPosition < mAdapter.getCount() - 1) {  
    634.   
    635. if (scrollToChild(mSelectedPosition + 1)) {  
    636.   
    637. mSelectedPosition ++;  
    638.   
    639. }  
    640.   
    641. }else if (velocityX > SNAP_VELOCITY && mSelectedPosition > 0) {  
    642.   
    643. if (scrollToChild(mSelectedPosition - 1)) {  
    644.   
    645. mSelectedPosition --;  
    646.   
    647. }  
    648.   
    649. }else{  
    650.   
    651. int position = calculteCenterItem();  
    652.   
    653. int newpostion = mFirstPosition + position;  
    654.   
    655. if (scrollToChild(newpostion)) {  
    656.   
    657. mSelectedPosition = newpostion;  
    658.   
    659. }  
    660.   
    661. }  
    662.   
    663. if (mVelocityTracker != null) {    
    664.   
    665.             mVelocityTracker.recycle();    
    666.   
    667.             mVelocityTracker = null;    
    668.   
    669.         }    
    670.   
    671. mTouchState = TOUCH_STATE_RESTING;  
    672.   
    673. }  
    674.   
    675. /** 
    676.  
    677.  * 计算最接近中心点的view 
    678.  
    679.  * @return 
    680.  
    681.  */  
    682.   
    683. private int calculteCenterItem(){  
    684.   
    685. View child = null;  
    686.   
    687. int lastpostion = 0;  
    688.   
    689. int lastclosestDistance = 0;  
    690.   
    691. int viewCenter = getLeft() + getWidth() / 2;  
    692.   
    693. for (int i = 0; i < getChildCount(); i++) {  
    694.   
    695. child = getChildAt(i);  
    696.   
    697. if (child.getLeft() < viewCenter && child.getRight() > viewCenter ) {  
    698.   
    699. lastpostion = i;  
    700.   
    701. break;  
    702.   
    703. }else {  
    704.   
    705. int childClosestDistance = Math.min(Math.abs(child.getLeft() - viewCenter), Math.abs(child.getRight() - viewCenter));  
    706.   
    707. if (childClosestDistance < lastclosestDistance) {  
    708.   
    709. lastclosestDistance = childClosestDistance;  
    710.   
    711. lastpostion = i;  
    712.   
    713. }  
    714.   
    715. }  
    716.   
    717. }  
    718.   
    719. return lastpostion;  
    720.   
    721. }  
    722.   
    723. public void moveNext(){  
    724.   
    725. if (!mScroller.isFinished()) {  
    726.   
    727. return;  
    728.   
    729. }  
    730.   
    731. if (0 <= mSelectedPosition && mSelectedPosition < mAdapter.getCount() - 1) {  
    732.   
    733. if (scrollToChild(mSelectedPosition + 1)) {  
    734.   
    735. mSelectedPosition ++;  
    736.   
    737. }else {  
    738.   
    739. makeAndAddView(mSelectedPosition + 11, getWidth(), true);  
    740.   
    741. if (scrollToChild(mSelectedPosition + 1)) {  
    742.   
    743. mSelectedPosition ++;  
    744.   
    745. }  
    746.   
    747. }  
    748.   
    749. }  
    750.   
    751. }  
    752.   
    753. public void movePrevious(){  
    754.   
    755. if (!mScroller.isFinished()) {  
    756.   
    757. return;  
    758.   
    759. }  
    760.   
    761. if (0 < mSelectedPosition && mSelectedPosition < mAdapter.getCount()) {  
    762.   
    763. if (scrollToChild(mSelectedPosition -1)) {  
    764.   
    765. mSelectedPosition --;  
    766.   
    767. }else {  
    768.   
    769. makeAndAddView(mSelectedPosition - 1, -10false);  
    770.   
    771. mFirstPosition = mSelectedPosition - 1;  
    772.   
    773. if (scrollToChild(mSelectedPosition - 1)) {  
    774.   
    775. mSelectedPosition --;  
    776.   
    777. }  
    778.   
    779. }  
    780.   
    781. }  
    782.   
    783. }  
    784.   
    785. private boolean scrollToChild(int position){  
    786.   
    787. MLog.d( "scrollToChild positionm,FirstPosition,childcount:"+position + "," + mFirstPosition+ "," + getChildCount());  
    788.   
    789. View child = getChildAt(position - mFirstPosition );  
    790.   
    791. if (child != null) {  
    792.   
    793. int distance = getWidth() / 2 - (child.getLeft() + child.getWidth() / 2);  
    794.   
    795. mLastScrolledOffset = 0;  
    796.   
    797. mScroller.startScroll(00, distance, 0,200);  
    798.   
    799. invalidate();  
    800.   
    801. return true;  
    802.   
    803. }  
    804.   
    805. MLog.d( "scrollToChild some error happened");  
    806.   
    807. return false;  
    808.   
    809. }  
    810.   
    811. @Override  
    812.   
    813. public void computeScroll() {  
    814.   
    815. if (mScroller.computeScrollOffset()) {  
    816.   
    817. int scrollX = mScroller.getCurrX();  
    818.   
    819. scrollDeltaX(scrollX - mLastScrolledOffset);  
    820.   
    821. mLastScrolledOffset = scrollX;  
    822.   
    823. postInvalidate();  
    824.   
    825. }  
    826.   
    827. }  
    828.   
    829. private void startTouch(MotionEvent event){  
    830.   
    831. mTouchStartX = event.getX();  
    832.   
    833. mTouchState = mScroller.isFinished()? TOUCH_STATE_RESTING : TOUCH_STATE_SCROLL;  
    834.   
    835. mLastMotionX = mTouchStartX;  
    836.   
    837. }  
    838.   
    839. private boolean startScrollIfNeeded(MotionEvent event){  
    840.   
    841. final int xPos = (int)event.getX();  
    842.   
    843.         mLastMotionX = event.getX();  
    844.   
    845.         if (xPos < mTouchStartX - mTouchSlop  
    846.   
    847.                 || xPos > mTouchStartX + mTouchSlop  
    848.   
    849.               ) {  
    850.   
    851.             // we've moved far enough for this to be a scroll  
    852.   
    853.             mTouchState = TOUCH_STATE_SCROLL;  
    854.   
    855.             return true;  
    856.   
    857.         }  
    858.   
    859.         return false;  
    860.   
    861. }  
    862.   
    863. /** 
    864.  
    865.      * Detaches children that are off the screen (i.e.: Gallery bounds). 
    866.  
    867.      * 
    868.  
    869.      * @param toLeft Whether to detach children to the left of the Gallery, or 
    870.  
    871.      *            to the right. 
    872.  
    873.      */  
    874.   
    875.     private void detachOffScreenChildren(boolean toLeft) {  
    876.   
    877.         int numChildren = getChildCount();  
    878.   
    879.         int start = 0;  
    880.   
    881.         int count = 0;  
    882.   
    883.         int firstPosition = mFirstPosition;  
    884.   
    885.         if (toLeft) {  
    886.   
    887.             final int galleryLeft = 0;  
    888.   
    889.             for (int i = 0; i < numChildren; i++) {  
    890.   
    891.                 final View child = getChildAt(i);  
    892.   
    893.                 if (child.getRight() >= galleryLeft) {  
    894.   
    895.                     break;  
    896.   
    897.                 } else {  
    898.   
    899.                     count++;  
    900.   
    901.                     mRecycler.put(firstPosition + i, child);  
    902.   
    903.                 }  
    904.   
    905.             }  
    906.   
    907.         } else {  
    908.   
    909.             final int galleryRight = getWidth();  
    910.   
    911.             for (int i = numChildren - 1; i >= 0; i--) {  
    912.   
    913.                 final View child = getChildAt(i);  
    914.   
    915.                 if (child.getLeft() <= galleryRight) {  
    916.   
    917.                     break;  
    918.   
    919.                 } else {  
    920.   
    921.                     start = i;  
    922.   
    923.                     count++;  
    924.   
    925.                     mRecycler.put(firstPosition + i, child);  
    926.   
    927.                 }  
    928.   
    929.             }  
    930.   
    931.         }  
    932.   
    933.         detachViewsFromParent(start, count);  
    934.   
    935.         if (toLeft) {  
    936.   
    937.             mFirstPosition += count;  
    938.   
    939.         }  
    940.          
    941.         mRecycler.clear();  
    942.   
    943.     }  
    944.   
    945.     public void setOnPositionChangeListen(OnPostionChangeListener onPostionChangeListener){  
    946.   
    947.             mOnPostionChangeListener = onPostionChangeListener;  
    948.   
    949.     }  
    950.   
    951.     public int getCurrentSelectedPosition(){  
    952.   
    953.             return mCurrentSelectedPosition;  
    954.   
    955.     }  
    956.   
    957.     /** 
    958.  
    959.      * 刷新数据,本来想用AdapterView.AdapterDataSetObserver机制来实现的,但是整个逻辑移植比较麻烦,就暂时用这个替代了 
    960.  
    961.      */  
    962.   
    963.     public void updateData(){  
    964.   
    965.             requestLayout();  
    966.   
    967.     }  
    968.   
    969.     private void recycleAllViews() {  
    970.   
    971.         int childCount = getChildCount();  
    972.   
    973.         final RecycleBin recycleBin = mRecycler;  
    974.   
    975.         // All views go in recycler  
    976.   
    977.         for (int i=0; i<childCount; i++) {  
    978.   
    979.             View v = getChildAt(i);  
    980.   
    981.             int index = mFirstPosition + i;  
    982.   
    983.             recycleBin.put(index, v);  
    984.   
    985.         }   
    986.   
    987.     }  
    988.   
    989.     class RecycleBin {  
    990.   
    991.         private SparseArray<View> mScrapHeap = new SparseArray<View>();  
    992.   
    993.         public void put(int position, View v) {  
    994.   
    995.              if (mScrapHeap.get(position) != null) {  
    996.   
    997.              Log.e(TAG,"RecycleBin put error.");  
    998.   
    999.             }  
    1000.   
    1001.             mScrapHeap.put(position, v);  
    1002.   
    1003.         }  
    1004.   
    1005.         View get(int position) {  
    1006.   
    1007.             // System.out.print("Looking for " + position);  
    1008.   
    1009.             View result = mScrapHeap.get(position);  
    1010.   
    1011.             if (result != null) {  
    1012.   
    1013.                     MLog.d("RecycleBin get hit.");  
    1014.   
    1015.                 mScrapHeap.delete(position);  
    1016.   
    1017.             } else {  
    1018.   
    1019.                     MLog.d("RecycleBin get Miss.");  
    1020.   
    1021.             }  
    1022.   
    1023.             return result;  
    1024.   
    1025.         }  
    1026.   
    1027.         View peek(int position) {  
    1028.   
    1029.             // System.out.print("Looking for " + position);  
    1030.   
    1031.             return mScrapHeap.get(position);  
    1032.   
    1033.         }  
    1034.   
    1035.         void clear() {  
    1036.   
    1037.             final SparseArray<View> scrapHeap = mScrapHeap;  
    1038.   
    1039.             final int count = scrapHeap.size();  
    1040.   
    1041.             for (int i = 0; i < count; i++) {  
    1042.   
    1043.                 final View view = scrapHeap.valueAt(i);  
    1044.   
    1045.                 if (view != null) {  
    1046.   
    1047.                     removeDetachedView(view, true);  
    1048.   
    1049.                 }  
    1050.   
    1051.             }  
    1052.   
    1053.             scrapHeap.clear();  
    1054.   
    1055.         }  
    1056.   
    1057.     }     
    1058.   
    1059.     public interface OnPostionChangeListener{  
    1060.   
    1061.             abstract public void onPostionChange(View v,int position);  
    1062.   
    1063.     }   
    1064.   

posted @ 2013-12-18 17:46  brave-sailor  阅读(423)  评论(0编辑  收藏  举报