nullpointer in Listview - getChildAt(getFirstVisiblePosition())

匿名 (未验证) 提交于 2019-12-03 09:06:55

问题:

I have a Listview with fullscreen pictures. (Like a vertical gallery). My problem is that I want to override the listviews onTouchEvent so that it only changes one picture at a time and so that after scrolling (When no fling occurs), the selected picure centers itself.

My problem is that when i call getChildAt(getFirstVisiblePosition()), it returns null. I allready checked and getFirstVisiblePosition() is returning a view that is vissible at the moment.

I'm using smoothScrollToPosition to center the pictures.

My code is verry long, but the important part is here: (when recieving a 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();     }  } 

Tank you in advance.


Because of the comment.

    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;         }     } 

And the adapter

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;     }    } 

NOTE: The picture changes on the device and the getFirstVisiblePosition() gives me the index of the first picture being shown. The problem is that getChildAt returns null with a view that is actually on screen.

回答1:

Solved my problem.

I didn't find the reason for the problem, but changing the code a little bit I got to trick the problem.

    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); 

What I did was to check if the view was null (even if it was being shown). If it was null I checked if the view over it was null, an so on until i go one that wasnt null on getChildAt(position).

When i found it, I used its position to calculate the position of the other view.

I also changed the code a little bit to use SmoothScrollBy insted os SmoothScrollToPosition because it made the view got perfectly centerded this way.

Now, If someone ever finds the reason for the problem, please tell me why its happening.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!