2011-05-02 60 views
1

我有一個ListView與全屏圖片。 (就像一個垂直的畫廊)。我的問題是我想重寫onTouchEvent的列表視圖,以便它一次只更改一張圖片,以便在滾動後(當沒有發生任何投影時),選定的圖片會自行居中。nullpointer

我的問題是,當我調用getChildAt(getFirstVisiblePosition())時,它返回null。我已經檢查並getFirstVisiblePosition()返回一個當前易於使用的視圖。

我正在使用smoothScrollToPosition居中圖片。

我的代碼很長,但重要的部分在這裏:(當接收MotionEvent.ACTION_UP時)。

case MotionEvent.ACTION_UP: 
{ 
    try 
    { 
     //Calculetes the velocity if the movement 
      int initialVelocity = (int)ModifiedVelocityTracker.getYVelocity();*/ 
     if (mVelocityTracker == null) 
     { 
      mVelocityTracker = VelocityTracker.obtain(); 
     } 
     final VelocityTracker ModifiedVelocityTracker = mVelocityTracker; 
     ModifiedVelocityTracker.computeCurrentVelocity(1000); 
     int initialVelocity = (int)ModifiedVelocityTracker.getYVelocity(); 

     //Detects if the motion is a fling 
     if ((Math.abs(initialVelocity) > 
     ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) && 
     (getChildCount() > 0)) // TODO FLing 
     { 
      super.onTouchEvent(getEventWithACTION_MOVE(ev)); 

      //Send the events to cancel the superclass fling 
      //MotionEvent me[] = mVelocityTracker.getTrickEvents(); 
      MotionEvent me[] = getTrickEvents(ev); 
      for(int i=0;i<me.length;i++) 
       super.onTouchEvent(me[i]); 

      int firstVisiblePosition = getFirstVisiblePosition(); 

      // Pint y=0 is located on the bottom, so a negative speed means 
      //the finger moved up and the picture to come is the one under 
      if(initialVelocity < 0) //EventUp-GoDown 
      { 
       if(firstVisiblePosition != getCount() - 1) //Can Move 
        { 
         //smoothScrollToPosition(firstVisiblePosition + 1); 
         View currentTopView = getChildAt(firstVisiblePosition); 
         int botom = currentTopView.getBottom(); 
         botom = botom - firstVisiblePosition * getHeight(); 
         smoothScrollBy(-botom, 500); 
        } else 
        { 
          smoothScrollToPosition(firstVisiblePosition); 
        } 
      } else //EventDown-GoUp 
      { 
       smoothScrollToPosition(firstVisiblePosition); 
      } 
     } 
     else // TODO Stay in the picture that has a bigger area shown 
     { 
      onTouchEvent = super.onTouchEvent(ev); 

      //Center The View after the parent stops moving it 

         /* 
         * FIREST VIEW |****|/SECOND VIEW | | 
         * 
         * CASE 1 Bottom over center - Set second view the main one 
         * |****| 
         * |****| Bottom of Top View at First visible Position 
         * | | 
         * |----| center line 
         * | | 
         * | | 
         * | | 
         * 
         * CASE 2 Bottom under center - Set first view the main one 
         * |****| 
         * |****| 
         * |****| 
         * |----| center line 
         * |****| 
         * |****| Bottom of Top View at First visible Position 
         * | | 
         * */ 

      int firstVisiblePosition = getFirstVisiblePosition(); 
      View currentTopView = getChildAt(firstVisiblePosition); 
      int botom; 
      if(currentTopView != null) 
      { 
       botom = currentTopView.getBottom(); 
      }else{ 
       currentTopView = getSelectedView(); 
       if(firstVisiblePosition == getPositionForView(currentTopView)) 
       { 
        botom = currentTopView.getBottom(); 
       } 
       else 
       { 
        botom = currentTopView.getTop(); 
       } 
      } 
      int center = getHeight()/2; 
      botom = botom - firstVisiblePosition * getHeight(); 
      if(botom < center) //Case 1 - Scroll Down 
      { 
       //Checks if the top view is the last one. 
        //Shouldn't happen, but just in case. 
       if(firstVisiblePosition != getCount() - 1) //Can Move 
       { 
        smoothScrollToPosition(firstVisiblePosition + 1); 

       } else 
       { 
        smoothScrollToPosition(firstVisiblePosition); 
       } 
      } 
      else //Case 2 
      { 
       smoothScrollToPosition(firstVisiblePosition); 
      } 
     } 
     onTouchEvent = true; 
    } catch(NullPointerException e) 
    { 
     e.printStackTrace(); 
    } 

} 

坦克你提前。


由於評論。

import android.content.Context; 
import android.os.SystemClock; 
import android.util.Log; 
import android.view.MotionEvent; 
import android.view.VelocityTracker; 
import android.view.View; 
import android.view.ViewConfiguration; 
import android.widget.ListView; 

public class FixedListView extends ListView{ 


    final static String LOGTAG = "TEST"; 

    private Context mContext; 
    VelocityTracker mVelocityTracker; 

    public FixedListView(Context context) { 
     super(context); 
     mContext = context; 
     setDivider(null); 
     // TODO Auto-generated constructor stub 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) 
    { 
     boolean onTouchEvent = true; 

     final int action = ev.getAction(); 

     //Add the event to the ModifiedVelocityTracker used for detect if if the motion is a fling (also creates it) 
     Log.d(LOGTAG, "Before add to Traker: " + SystemClock.uptimeMillis()); 
     /*if (mVelocityTracker == null) 
     { 
      mVelocityTracker = ModifiedVelocityTracker.obtain(); 
     } 
     mVelocityTracker.addMovement(ev);*/ 
     Log.d(LOGTAG, "After add to Traker: " + SystemClock.uptimeMillis()); 
     //Detect the event action type 
     switch (action) { 
      case MotionEvent.ACTION_DOWN: 
      case MotionEvent.ACTION_MOVE: 
      { 
       Log.d(LOGTAG, "After eval action Traker: " + SystemClock.uptimeMillis()); 
       onTouchEvent = super.onTouchEvent(ev); 
       Log.d(LOGTAG, "After super Y = " + ev.getY() +": " + SystemClock.uptimeMillis()); 
       break; 
      } 
      case MotionEvent.ACTION_UP: 
      { 
       try 
       { 
        //Calculetes the velocity if the movement 
        //NOTE: I'm using my own VelocityTraker because the Android.Utils 
        //one can only be used once at a time and the superclass uses it. 
        /*final ModifiedVelocityTracker ModifiedVelocityTracker = mVelocityTracker; 
        ModifiedVelocityTracker.computeCurrentVelocity(1000); 
        int initialVelocity = (int)ModifiedVelocityTracker.getYVelocity();*/ 
        if (mVelocityTracker == null) 
        { 
         mVelocityTracker = VelocityTracker.obtain(); 
        } 
        final VelocityTracker ModifiedVelocityTracker = mVelocityTracker; 
        ModifiedVelocityTracker.computeCurrentVelocity(1000); 
        int initialVelocity = (int)ModifiedVelocityTracker.getYVelocity(); 

        //Detects if the motion is a fling 
        if ((Math.abs(initialVelocity) > 
        ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) && 
        (getChildCount() > 0)) // TODO FLing 
        { 
         super.onTouchEvent(getEventWithACTION_MOVE(ev)); 

         //Send the events to cancel the superclass fling 
         //MotionEvent me[] = mVelocityTracker.getTrickEvents(); 
         MotionEvent me[] = getTrickEvents(ev); 
         for(int i=0;i<me.length;i++) 
          super.onTouchEvent(me[i]); 

         int firstVisiblePosition = getFirstVisiblePosition(); 

         // Pint y=0 is located on the bottom, so a negative speed means 
         //the finger moved up and the picture to come is the one under 
         if(initialVelocity < 0) //EventUp-GoDown 
         { 
          if(firstVisiblePosition != getCount() - 1) //Can Move 
          { 
           //smoothScrollToPosition(firstVisiblePosition + 1); 
           View currentTopView = getChildAt(firstVisiblePosition); 
           int botom = currentTopView.getBottom(); 
           botom = botom - firstVisiblePosition * getHeight(); 
           smoothScrollBy(-botom, 500); 
          } else 
          { 
           smoothScrollToPosition(firstVisiblePosition); 
          } 
         } else //EventDown-GoUp 
         { 
           smoothScrollToPosition(firstVisiblePosition); 
         } 
        } 
        else // TODO Stay in the picture that has a bigger area shown 
        { 
         onTouchEvent = super.onTouchEvent(ev); 

         //Center The View after the parent stops moving it 

         /* 
         * FIREST VIEW |****|/SECOND VIEW | | 
         * 
         * CASE 1 Bottom over center - Set second view the main one 
         * |****| 
         * |****| Bottom of Top View at First visible Position 
         * | | 
         * |----| center line 
         * | | 
         * | | 
         * | | 
         * 
         * CASE 2 Bottom under center - Set first view the main one 
         * |****| 
         * |****| 
         * |****| 
         * |----| center line 
         * |****| 
         * |****| Bottom of Top View at First visible Position 
         * | | 
         * */ 

         int firstVisiblePosition = getFirstVisiblePosition(); 
         View currentTopView = getChildAt(firstVisiblePosition); 
         int botom; 
         if(currentTopView != null) 
         { 
          botom = currentTopView.getBottom(); 
         }else{ 
          currentTopView = getSelectedView(); 
          if(firstVisiblePosition == getPositionForView(currentTopView)) 
          { 
           botom = currentTopView.getBottom(); 
          } 
          else 
          { 
           botom = currentTopView.getTop(); 
          } 
         } 
         int center = getHeight()/2; 
         botom = botom - firstVisiblePosition * getHeight(); 
         if(botom < center) //Case 1 - Scroll Down 
         { 
          //Checks if the top view is the last one. 
          //Shouldn't happen, but just in case. 
          if(firstVisiblePosition != getCount() - 1) //Can Move 
          { 
           smoothScrollToPosition(firstVisiblePosition + 1); 

          } else 
          { 
           smoothScrollToPosition(firstVisiblePosition); 
          } 
         } 
         else //Case 2 
         { 

          smoothScrollToPosition(firstVisiblePosition); 
         } 
        } 
        onTouchEvent = true; 
       } catch(NullPointerException e) 
       { 
        e.printStackTrace(); 
       } 
       if(mVelocityTracker != null) 
        mVelocityTracker.recycle(); 
       break; 
      } 
      case MotionEvent.ACTION_CANCEL: 
      { 
       try 
       { 
        onTouchEvent = super.onTouchEvent(ev); 

        //Center The View after the parent stops moving it 

        /* 
        * FIREST VIEW |****|/SECOND VIEW | | 
        * 
        * CASE 1 Bottom over center - Set second view the main one 
        * |****| 
        * |****| Bottom of Top View at First visible Position 
        * | | 
        * |----| center line 
        * | | 
        * | | 
        * | | 
        * 
        * CASE 2 Bottom under center - Set first view the main one 
        * |****| 
        * |****| 
        * |****| 
        * |----| center line 
        * |****| 
        * |****| Bottom of Top View at First visible Position 
        * | | 
        * */ 

        int firstVisiblePosition = getFirstVisiblePosition(); 
        View currentTopView = getChildAt(firstVisiblePosition); 
        int center = getHeight()/2; 
        if(currentTopView.getBottom() < center) //Case 1 - Scroll Down 
        { 
         //Checks if the top view is the last one. 
         //Shouldn't happen, but just in case. 
         if(firstVisiblePosition != getCount() - 1) //Can Move 
         { 
          smoothScrollToPosition(firstVisiblePosition + 1); 
         } else 
         { 
          smoothScrollToPosition(firstVisiblePosition); 
         } 
        } 
        else //Case 2 
        { 
         if(firstVisiblePosition != 0) //Can Move 
         { 
          smoothScrollToPosition(firstVisiblePosition - 1); 
         } else 
         { 
          smoothScrollToPosition(firstVisiblePosition); 
         } 
        } 
        onTouchEvent = true; 
       } catch(NullPointerException e) 
       { 
        e.printStackTrace(); 
       } 
       if(mVelocityTracker != null) 
       { 
        mVelocityTracker.recycle(); 
        mVelocityTracker = null; 
       } 
      } 
     } 

     // TODO Auto-generated method stub 
     return onTouchEvent; 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     // TODO Auto-generated method stub 
     return super.onInterceptTouchEvent(ev); 
    } 


    public MotionEvent[] getTrickEvents(MotionEvent ev) 
    { 
     //Detect the last touched position 
     final float requiredX = ev.getX(); 
     final float requiredY = ev.getY(); 

     //Get a time value that is longer than the last added event value by a bigger 
     //number than the LONGEST_PAST_TIME accepted by the VelocityTraker 
     //NOTE: If GOOGLE changes the LONGEST_PAST_TIME, we will have to change it too, 
     //I wasn't able to retrieve the original VelocityTracker LONGEST_PAST_TIME directly from it. 
     final long requiredPastTime = ev.getEventTime() + 201; 

     //Create the MotionEvents (Simulating no movement in y). 
     MotionEvent m1 = null; 
     if(requiredX == 0) //If at the left border, move one pixel to the right. 
     { 
      m1 = MotionEvent.obtain(requiredPastTime, requiredPastTime, 
        MotionEvent.ACTION_MOVE, 
        requiredX + 1, requiredY, 0); 
     } 
     else //If not at the left border, move one pixel to the left 
     { 
      m1 = MotionEvent.obtain(requiredPastTime, requiredPastTime, 
        MotionEvent.ACTION_MOVE, 
        requiredX - 1, requiredY, 0); 
     } 
     //Return to the original position after 100 time units 
     MotionEvent m2 = MotionEvent.obtain(requiredPastTime + 100, requiredPastTime + 100, 
       MotionEvent.ACTION_UP, 
       requiredX, requiredY, 0); 
     MotionEvent motEvents[] = {m1,m2}; 

     return motEvents; 
    } 

    public MotionEvent getEventWithACTION_MOVE(MotionEvent ev) 
    { 
     //Detect the last touched position 
     final float requiredX = ev.getX(); 
     final float requiredY = ev.getY(); 

     //Get a time value that is longer than the last added event value by a bigger 
     //number than the LONGEST_PAST_TIME accepted by the VelocityTraker 
     //NOTE: If GOOGLE changes the LONGEST_PAST_TIME, we will have to change it too, 
     //I wasn't able to retrieve the original VelocityTracker LONGEST_PAST_TIME directly from it. 
     final long Time = ev.getEventTime(); 

     //Create the MotionEvent 
     MotionEvent m1 = MotionEvent.obtain(Time, Time, 
        MotionEvent.ACTION_MOVE, 
        requiredX , requiredY, 0); 

     return m1; 
     } 
    } 

和適配器

public class FixedListAdapter extends BaseAdapter 
{ 
    int pictures[]; 

    public FixedListAdapter(int pictures[]) 
    { 
     this.pictures = pictures; 
    } 

    public int getCount() { 
     return pictures.length; 
    } 

    public Object getItem(int position) { 
     return pictures[position]; 
    } 

    public long getItemId(int position) { 
     return pictures[position]; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     LinearLayout l = new LinearLayout(GalleryTest.this); 
     l.setLayoutParams(new ListView.LayoutParams(
       ListView.LayoutParams.MATCH_PARENT, ListView.LayoutParams.MATCH_PARENT)); 
     l.setGravity(Gravity.CENTER); 
     l.setPadding(0,0,0,0); 
     l.setBackgroundColor(Color.BLACK); 

     ImageView i = new ImageView(GalleryTest.this); 
     i.setLayoutParams(new LinearLayout.LayoutParams(width, height)); 
     i.setScaleType(ImageView.ScaleType.FIT_CENTER); 
     i.setImageResource(pictures[position]); 

     l.addView(i); 
     return l; 
    } 



} 

注:在設備和getFirstVisiblePosition上的圖像的變化()給我的第一圖片的索引被顯示。問題是,getChildAt返回null,實際上是在屏幕上的視圖。

+0

爲了以防萬一,我正在處理ListView的子類。 – 2011-05-02 21:11:53

+0

如果您在該代碼中的getChildAt()處得到null,那麼您包含的內容不是重要的部分。我們需要看到更多的上下文,因爲沒有_there_會解釋爲什麼它返回null。 – 2011-05-02 21:31:26

+0

好的,我會複製整個班級。我也會複製適配器。感謝您查看此內容。 – 2011-05-02 21:37:25

回答

1

解決了我的問題。

我沒有找到問題的原因,但改變了一些代碼我欺騙了問題。

int firstVisiblePosition = getFirstVisiblePosition(); 

View currentTopView = getChildAt(firstVisiblePosition); 
int transpose = 0; 

while(currentTopView == null) 
{ 
    transpose++; 
    currentTopView = getChildAt(firstVisiblePosition - transpose); 
} 
int botom = currentTopView.getBottom(); 
int top = currentTopView.getTop(); 
int height = getHeight(); 
botom = botom + height * (transpose - firstVisiblePosition); 
top = top + height * (transpose - firstVisiblePosition); 

我所做的是檢查視圖是否爲空(即使它被顯示)。如果它是空的,我檢查它的視圖是否爲空,直到我去到一個不爲空的getChildAt(position)

當我找到它時,我用它的位置來計算另一個視圖的位置。

我也改變了一些代碼來使用SmoothScrollBy insted os SmoothScrollToPosition,因爲它使視圖完​​全以這種方式爲中心。

現在,如果有人發現問題的原因,請告訴我爲什麼發生這種情況。

+1

getFirstVisiblePosition()是視圖在適配器中的位置而不是listview。 第一個看不見的孩子將總是由getChildAt(0)來解決; 當firstVisiblePosition = transpose時,你的代碼給出了正確的結果 – Diljeet 2012-11-10 12:27:25