Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> android UI 優化之 AbsListView之深度優化

android UI 優化之 AbsListView之深度優化

編輯:Android開發實例

android 提供的很多List控件如 listview、gridview 默認都會顯示一個fadingedge的東西,它在View的top和bottom處各顯示一個漸變半透的陰影以達到更好的視覺效果,但是這個帶來的副作用就是導致在性能不是那麼強勁的機器上,一些listview,gridview的拖動會顯得很不流暢,因為我們知道繪制帶Alpha的圖片是最耗時的。 
 
我們的優化思路就是對這個fadingedge做一些修改,當view處於滾動狀態時,通過接口setVerticalFadingEdgeEnabled(false)讓其不顯示fadingedge,當view處於靜止狀態時,通過接口setVerticalFadingEdgeEnabled(true)恢復顯示fadingedge。以上的listview和gridview等控件都是繼承與AbsListView,所以我們直接修改framework中的AbsListView.java文件,就可以達到系統級的改動效果了。 
 
具體修改如下: 

 

  1. @Override   
  2. public boolean onTouchEvent(MotionEvent ev) {   
  3.     if (!isEnabled()) {   
  4.         // A disabled view that is clickable still consumes the touch   
  5.         // events, it just doesn't respond to them.   
  6.         return isClickable() || isLongClickable();   
  7.     }   
  8.     if (mFastScroller != null) {   
  9.         boolean intercepted = mFastScroller.onTouchEvent(ev);   
  10.         if (intercepted) {   
  11.             return true;   
  12.         }   
  13.     }   
  14.     final int action = ev.getAction();   
  15.     View v;   
  16.     int deltaY;   
  17.     if (mVelocityTracker == null) {   
  18.         mVelocityTracker = VelocityTracker.obtain();   
  19.     }   
  20.     mVelocityTracker.addMovement(ev);   
  21.     switch (action & MotionEvent.ACTION_MASK) {   
  22.     case MotionEvent.ACTION_DOWN: {   
  23.         setVerticalFadingEdgeEnabled(false);   
  24.         mActivePointerId = ev.getPointerId(0);   
  25.         final int x = (int) ev.getX();   
  26.         final int y = (int) ev.getY();   
  27.         int motionPosition = pointToPosition(x, y);   
  28.         if (!mDataChanged) {   
  29.             if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)   
  30.                     && (getAdapter().isEnabled(motionPosition))) {   
  31.                 // User clicked on an actual view (and was not stopping a fling). It might be a   
  32.                 // click or a scroll. Assume it is a click until proven otherwise   
  33.                 mTouchMode = TOUCH_MODE_DOWN;   
  34.                 // FIXME Debounce   
  35.                 if (mPendingCheckForTap == null) {   
  36.                     mPendingCheckForTap = new CheckForTap();   
  37.                 }   
  38.                 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());   
  39.             } else {   
  40.                 if (ev.getEdgeFlags() != 0 && motionPosition < 0) {   
  41.                     // If we couldn't find a view to click on, but the down event was touching   
  42.                     // the edge, we will bail out and try again. This allows the edge correcting   
  43.                     // code in ViewRoot to try to find a nearby view to select   
  44.                     return false;   
  45.                 }   
  46.                 if (mTouchMode == TOUCH_MODE_FLING) {   
  47.                     // Stopped a fling. It is a scroll.   
  48.                     createScrollingCache();   
  49.                     mTouchMode = TOUCH_MODE_SCROLL;   
  50.                     mMotionCorrection = 0;   
  51.                     motionPosition = findMotionRow(y);   
  52.                     reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);   
  53.                 }   
  54.             }   
  55.         }   
  56.         if (motionPosition >= 0) {   
  57.             // Remember where the motion event started   
  58.             v = getChildAt(motionPosition - mFirstPosition);   
  59.             mMotionViewOriginalTop = v.getTop();   
  60.         }   
  61.         mMotionX = x;   
  62.         mMotionY = y;   
  63.         mMotionPosition = motionPosition;   
  64.         mLastY = Integer.MIN_VALUE;   
  65.         break;   
  66.     }   
  67.     case MotionEvent.ACTION_MOVE: {   
  68.         final int pointerIndex = ev.findPointerIndex(mActivePointerId);   
  69.         final int y = (int) ev.getY(pointerIndex);   
  70.         deltaY = y - mMotionY;   
  71.         switch (mTouchMode) {   
  72.         case TOUCH_MODE_DOWN:   
  73.         case TOUCH_MODE_TAP:   
  74.         case TOUCH_MODE_DONE_WAITING:   
  75.             // Check if we have moved far enough that it looks more like a   
  76.             // scroll than a tap   
  77.             startScrollIfNeeded(deltaY);   
  78.             break;   
  79.         case TOUCH_MODE_SCROLL:   
  80.             if (PROFILE_SCROLLING) {   
  81.                 if (!mScrollProfilingStarted) {   
  82.                     Debug.startMethodTracing("AbsListViewScroll");   
  83.                     mScrollProfilingStarted = true;   
  84.                 }   
  85.             }   
  86.             if (y != mLastY) {   
  87.                 deltaY -= mMotionCorrection;   
  88.                 int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;   
  89.                    
  90.                 // No need to do all this work if we're not going to move anyway   
  91.                 boolean atEdge = false;   
  92.                 if (incrementalDeltaY != 0) {   
  93.                     atEdge = trackMotionScroll(deltaY, incrementalDeltaY);   
  94.                 }   
  95.                 // Check to see if we have bumped into the scroll limit   
  96.                 if (atEdge && getChildCount() > 0) {   
  97.                     // Treat this like we're starting a new scroll from the current   
  98.                     // position. This will let the user start scrolling back into   
  99.                     // content immediately rather than needing to scroll back to the   
  100.                     // point where they hit the limit first.   
  101.                     int motionPosition = findMotionRow(y);   
  102.                     if (motionPosition >= 0) {   
  103.                         final View motionView = getChildAt(motionPosition - mFirstPosition);   
  104.                         mMotionViewOriginalTop = motionView.getTop();   
  105.                     }   
  106.                     mMotionY = y;   
  107.                     mMotionPosition = motionPosition;   
  108.                     invalidate();   
  109.                 }   
  110.                 mLastY = y;   
  111.             }   
  112.             break;   
  113.         }   
  114.         break;   
  115.     }   
  116.     case MotionEvent.ACTION_UP: {   
  117.         switch (mTouchMode) {   
  118.         case TOUCH_MODE_DOWN:   
  119.         case TOUCH_MODE_TAP:   
  120.         case TOUCH_MODE_DONE_WAITING:   
  121.             setVerticalFadingEdgeEnabled(true);   
  122.             final int motionPosition = mMotionPosition;   
  123.             final View child = getChildAt(motionPosition - mFirstPosition);   
  124.             if (child != null && !child.hasFocusable()) {   
  125.                 if (mTouchMode != TOUCH_MODE_DOWN) {   
  126.                     child.setPressed(false);   
  127.                 }   
  128.                 if (mPerformClick == null) {   
  129.                     mPerformClick = new PerformClick();   
  130.                 }   
  131.                 final AbsListView.PerformClick performClick = mPerformClick;   
  132.                 performClick.mChild = child;   
  133.                 performClick.mClickMotionPosition = motionPosition;   
  134.                 performClick.rememberWindowAttachCount();   
  135.                 mResurrectToPosition = motionPosition;   
  136.                 if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP) {   
  137.                     final Handler handler = getHandler();   
  138.                     if (handler != null) {   
  139.                         handler.removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ?   
  140.                                 mPendingCheckForTap : mPendingCheckForLongPress);   
  141.                     }   
  142.                     mLayoutMode = LAYOUT_NORMAL;   
  143.                     if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {   
  144.                         mTouchMode = TOUCH_MODE_TAP;   
  145.                         setSelectedPositionInt(mMotionPosition);   
  146.                         layoutChildren();   
  147.                         child.setPressed(true);   
  148.                         positionSelector(child);   
  149.                         setPressed(true);   
  150.                         if (mSelector != null) {   
  151.                             Drawable d = mSelector.getCurrent();   
  152.                             if (d != null && d instanceof TransitionDrawable) {   
  153.                                 ((TransitionDrawable) d).resetTransition();   
  154.                             }   
  155.                         }   
  156.                         postDelayed(new Runnable() {   
  157.                             public void run() {   
  158.                                 child.setPressed(false);   
  159.                                 setPressed(false);   
  160.                                 if (!mDataChanged) {   
  161.                                     post(performClick);   
  162.                                 }   
  163.                                 mTouchMode = TOUCH_MODE_REST;   
  164.                             }   
  165.                         }, ViewConfiguration.getPressedStateDuration());   
  166.                     } else {   
  167.                         mTouchMode = TOUCH_MODE_REST;   
  168.                     }   
  169.                     return true;   
  170.                 } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {   
  171.                     post(performClick);   
  172.                 }   
  173.             }   
  174.             mTouchMode = TOUCH_MODE_REST;   
  175.             break;   
  176.         case TOUCH_MODE_SCROLL:   
  177.             final int childCount = getChildCount();   
  178.             if (childCount > 0) {   
  179.                 if (mFirstPosition == 0 && getChildAt(0).getTop() >= mListPadding.top &&   
  180.                         mFirstPosition + childCount < mItemCount &&   
  181.                         getChildAt(childCount - 1).getBottom() <=   
  182.                                 getHeight() - mListPadding.bottom) {   
  183.                     mTouchMode = TOUCH_MODE_REST;   
  184.                     reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);   
  185.                     setVerticalFadingEdgeEnabled(true);   
  186.                 } else {   
  187.                     final VelocityTracker velocityTracker = mVelocityTracker;   
  188.                     velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);   
  189.                     final int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);   
  190.    
  191.                     if (Math.abs(initialVelocity) > mMinimumVelocity) {   
  192.                         if (mFlingRunnable == null) {   
  193.                             mFlingRunnable = new FlingRunnable();   
  194.                         }   
  195.                         reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);   
  196.                            
  197.                         mFlingRunnable.start(-initialVelocity);   
  198.                     } else {   
  199.                         mTouchMode = TOUCH_MODE_REST;   
  200.                         reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);   
  201.                         setVerticalFadingEdgeEnabled(true);   
  202.                     }   
  203.                 }   
  204.             } else {   
  205.                 mTouchMode = TOUCH_MODE_REST;   
  206.                 reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);   
  207.                 setVerticalFadingEdgeEnabled(true);   
  208.             }   
  209.             break;   
  210.         }   
  211.         setPressed(false);   
  212.         // Need to redraw since we probably aren't drawing the selector anymore   
  213.         invalidate();   
  214.         final Handler handler = getHandler();   
  215.         if (handler != null) {   
  216.             handler.removeCallbacks(mPendingCheckForLongPress);   
  217.         }   
  218.         if (mVelocityTracker != null) {   
  219.             mVelocityTracker.recycle();   
  220.             mVelocityTracker = null;   
  221.         }   
  222.            
  223.         mActivePointerId = INVALID_POINTER;   
  224.         if (PROFILE_SCROLLING) {   
  225.             if (mScrollProfilingStarted) {   
  226.                 Debug.stopMethodTracing();   
  227.                 mScrollProfilingStarted = false;   
  228.             }   
  229.         }   
  230.         break;   
  231.     }   
  232.     case MotionEvent.ACTION_CANCEL: {   
  233.         mTouchMode = TOUCH_MODE_REST;   
  234.         setPressed(false);   
  235.         View motionView = this.getChildAt(mMotionPosition - mFirstPosition);   
  236.         if (motionView != null) {   
  237.             motionView.setPressed(false);   
  238.         }   
  239.         clearScrollingCache();   
  240.         final Handler handler = getHandler();   
  241.         if (handler != null) {   
  242.             handler.removeCallbacks(mPendingCheckForLongPress);   
  243.         }   
  244.         if (mVelocityTracker != null) {   
  245.             mVelocityTracker.recycle();   
  246.             mVelocityTracker = null;   
  247.         }   
  248.            
  249.         mActivePointerId = INVALID_POINTER;   
  250.         break;   
  251.     }   
  252.        
  253.     case MotionEvent.ACTION_POINTER_UP: {   
  254.         onSecondaryPointerUp(ev);   
  255.         final int x = mMotionX;   
  256.         final int y = mMotionY;   
  257.         final int motionPosition = pointToPosition(x, y);   
  258.         if (motionPosition >= 0) {   
  259.             // Remember where the motion event started   
  260.             v = getChildAt(motionPosition - mFirstPosition);   
  261.             mMotionViewOriginalTop = v.getTop();   
  262.             mMotionPosition = motionPosition;   
  263.         }   
  264.         mLastY = y;   
  265.         break;   
  266.     }   
  267.     }   
  268.     return true;   
  269. }   
  270. ====================================================================   
  271. private class FlingRunnable implements Runnable {   
  272.        
  273.     private final Scroller mScroller;   
  274.        
  275.     private int mLastFlingY;   
  276.     FlingRunnable() {   
  277.         mScroller = new Scroller(getContext());   
  278.     }   
  279.     void start(int initialVelocity) {   
  280.         int initialY = initialVelocity < 0 ? Integer.MAX_VALUE : 0;   
  281.         mLastFlingY = initialY;   
  282.         mScroller.fling(0, initialY, 0, initialVelocity,   
  283.                 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);   
  284.         mTouchMode = TOUCH_MODE_FLING;   
  285.         post(this);   
  286.         if (PROFILE_FLINGING) {   
  287.             if (!mFlingProfilingStarted) {   
  288.                 Debug.startMethodTracing("AbsListViewFling");   
  289.                 mFlingProfilingStarted = true;   
  290.             }   
  291.         }   
  292.     }   
  293.     void startScroll(int distance, int duration) {   
  294.         int initialY = distance < 0 ? Integer.MAX_VALUE : 0;   
  295.         mLastFlingY = initialY;   
  296.         mScroller.startScroll(0, initialY, 0, distance, duration);   
  297.         mTouchMode = TOUCH_MODE_FLING;   
  298.         post(this);   
  299.     }   
  300.     private void endFling() {   
  301.         mTouchMode = TOUCH_MODE_REST;   
  302.         reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);   
  303.         clearScrollingCache();   
  304.         removeCallbacks(this);   
  305.         if (mPositionScroller != null) {   
  306.             removeCallbacks(mPositionScroller);   
  307.         }   
  308.     }   
  309.     public void run() {   
  310.         switch (mTouchMode) {   
  311.         default:   
  312.             return;   
  313.                
  314.         case TOUCH_MODE_FLING: {   
  315.             if (mItemCount == 0 || getChildCount() == 0) {   
  316.                 endFling();   
  317.                 return;   
  318.             }   
  319.             final Scroller scroller = mScroller;   
  320.             boolean more = scroller.computeScrollOffset();   
  321.             final int y = scroller.getCurrY();   
  322.             // Flip sign to convert finger direction to list items direction   
  323.             // (e.g. finger moving down means list is moving towards the top)   
  324.             int delta = mLastFlingY - y;   
  325.             // Pretend that each frame of a fling scroll is a touch scroll   
  326.             if (delta > 0) {   
  327.                 // List is moving towards the top. Use first view as mMotionPosition   
  328.                 mMotionPosition = mFirstPosition;   
  329.                 final View firstView = getChildAt(0);   
  330.                 mMotionViewOriginalTop = firstView.getTop();   
  331.                 // Don't fling more than 1 screen   
  332.                 delta = Math.min(getHeight() - mPaddingBottom - mPaddingTop - 1, delta);   
  333.             } else {   
  334.                 // List is moving towards the bottom. Use last view as mMotionPosition   
  335.                 int offsetToLast = getChildCount() - 1;   
  336.                 mMotionPosition = mFirstPosition + offsetToLast;   
  337.                 final View lastView = getChildAt(offsetToLast);   
  338.                 mMotionViewOriginalTop = lastView.getTop();   
  339.                 // Don't fling more than 1 screen   
  340.                 delta = Math.max(-(getHeight() - mPaddingBottom - mPaddingTop - 1), delta);   
  341.             }   
  342.             final boolean atEnd = trackMotionScroll(delta, delta);   
  343.             if (more && !atEnd) {   
  344.                 invalidate();   
  345.                 mLastFlingY = y;   
  346.                 post(this);   
  347.             } else {   
  348.                 endFling();   
  349.                 AbsListView.this.setVerticalFadingEdgeEnabled(true);   
  350.                 if (PROFILE_FLINGING) {   
  351.                     if (mFlingProfilingStarted) {   
  352.                         Debug.stopMethodTracing();   
  353.                         mFlingProfilingStarted = false;   
  354.                     }   
  355.                 }   
  356.             }   
  357.             break;   
  358.         }   
  359.         }   
  360.     }   
  361. }   


 
修改後重新編譯,在性能稍差的機器上運行,滾動一下listview或者gridview,你就可以看到比較明顯的效果了!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved