Horizontal slide List Implementation Method, horizontal slide list

Source: Internet
Author: User

Horizontal slide List Implementation Method, horizontal slide list
List of horizontal slides

?? In Android development, sometimes the list width is insufficient to display all data. If you do not want to use two-level display (that is, the List displays limited data, click to go to the new page to display detailed data) You need a list that can slide left and right to display more data. However, either ListView, ExpandableListView, or even ScrollView does not have this capability, therefore, a different approach is required to implement this function.

Simple and Direct Solution

?? The idea of the first solution is very simple and straightforward. Among the basic components provided by Android, there is a slidable component called HorizontalScrollView, which is similar to ScrollView and provides identical functions, the only difference is that ScrollView slides vertically by default, and HorizontalScrollView slides horizontally by default. This component is suitable for meeting the previously mentioned requirements.
?? The method is simple. You only need to put the ListView or ExpandableListView into the HorizontalScrollView and use it normally. After running, the list can be freely moved up or down or left or right.
?? It should be noted that, because HorizontalScrollView can slide left and right, internal components such as ListView should not be determined by parameters such as match_parent, which will lead to insufficient width and fail to slide; the subitem used in the list also needs to have a fixed width. It is best to write it in the XML file (of course, you can also set it in the getView method ).
?? The Code is as follows:
??XML layout File

     
          
           
       
  
 

?? Place this part of code to the place where this list is needed. Note that the width of the List and its parent container is wrap_content. The height of HorizontalScrollView can be customized as needed.
?? During use, you only need to follow the ListView usage normally.

Solve more flexible needs

?? The first simple and easy-to-use solution can solve most of the requirements, but sometimes it can still meet more special requirements that need to be solved. At this time, the simple solution may not be enough.
?? For example, if you want to slide the sublist section of the ExpandableListView, or want the list to change the display height as required, for example, to show five at the beginning, click expand to show all; alternatively, you can slide only one part of the list to the left or right, but not the other part. If you need a floating display header, it also needs to slide along with the list. These diverse and flexible needs may cause obstacles if you continue to use the first simple solution.
?? Is there a second idea? The answer is yes. Since ListView can be placed in HorizontalScrollView, it is completely feasible in turn, and because HorizontalScrollView becomes an internal subitem of ListView, it is more flexible to control.
?? Now let's assume a demand scenario: a series of data needs to be presented, such as the Personal technical statistics of Basketball Players. Many projects need to be displayed horizontally slide, and the players' names must not be moved, only technical statistical items can be moved. At the same time, because there are only five people starting the game and the Team has more people than this number, an expansion function is required. When displaying data, you need to tell the user what each data in the table means, therefore, a floating header is required to prompt
?? This requirement combines all the possibilities mentioned above to implement it now.
?? Since the train of thought should be reversed, that is to say, to put the HorizontalScrollView into the ListView as its sub-item, and only a part of data can be slide, you can write the following sub-item XML layout.

     
      
           
                
                     
       
        
         
          
           
            
             
              
             
            
           
          
         
        
       
      
             
        
   
  
 

?? Considering that normal HorizontalScrollView cannot meet the requirements, because each subitem of ListView is separated and has a reuse mechanism, a component meeting the requirements needs to be designed.
?? To design this component, you must first clearly design its purpose, that is, to allow all the items displayed on the table to slide horizontally as any item, new sub-items under the reuse mechanism must be quickly switched to the appropriate position.
?? The following InnerHorizontalScrollView can be designed accordingly.

public class InnerHorizontalScrollView extends HorizontalScrollView {    private ScrollViewObserver scrollViewObserver;    private int grpIndex;    public InnerHorizontalScrollView(Context context) {        super(context);        initAttr();        // TODO Auto-generated constructor stub    }    public InnerHorizontalScrollView(Context context, AttributeSet attrs) {        super(context, attrs);        initAttr();        // TODO Auto-generated constructor stub    }    public InnerHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initAttr();        // TODO Auto-generated constructor stub    }    public void addOnScrollChangedListener(OnScrollChangedListener listener) {        scrollViewObserver.AddOnScrollChangedListener(listener);    }    public void removeOnScrollChangedListener(OnScrollChangedListener listener) {        scrollViewObserver.RemoveOnScrollChangedListener(listener);    }    public void setGrpIndex(int grpIndex) {        this.grpIndex = grpIndex;        scrollViewObserver.setgIndex(this.grpIndex);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        // TODO Auto-generated method stub        return super.onTouchEvent(ev);    }    @Override    protected void onScrollChanged(int l, int t, int oldl, int oldt) {        // TODO Auto-generated method stub        if (scrollViewObserver != null) {            scrollViewObserver.NotifyOnScrollChanged(l, t, oldl, oldt);        }        super.onScrollChanged(l, t, oldl, oldt);    }    private void initAttr() {        scrollViewObserver = new ScrollViewObserver();        grpIndex = -1;    }    public static interface OnScrollChangedListener {        public void onScrollChanged(int l, int t, int oldl, int oldt, int grp);    }    public static class ScrollViewObserver {        List
 
   mList;        LTPair ltcache;        LTPair oldltcache;        int gIndex;        public ScrollViewObserver() {            super();            mList = new ArrayList
  
   ();            ltcache = new LTPair();            oldltcache = new LTPair();            gIndex = -1;        }        public void setgIndex(int gIndex) {            this.gIndex = gIndex;        }        public void AddOnScrollChangedListener(OnScrollChangedListener listener) {            listener.onScrollChanged(ltcache.l, ltcache.t, oldltcache.l, oldltcache.t, gIndex);            if (!mList.contains(listener)) {                mList.add(listener);            }        }        public void RemoveOnScrollChangedListener(                OnScrollChangedListener listener) {            mList.remove(listener);        }        public void NotifyOnScrollChanged(int l, int t, int oldl, int oldt) {            if (mList == null || mList.size() == 0) {                return;            }            ltcache.l = l;            ltcache.t = t;            oldltcache.l = oldl;            oldltcache.t = oldt;            for (int i = 0; i < mList.size(); i++) {                if (mList.get(i) != null) {                    mList.get(i).onScrollChanged(l, t, oldl, oldt, gIndex);                }            }        }        private class LTPair {            public int l;            public int t;        }    }}
  
 

?? An OnScrollChangedListener interface is designed in the class, and the ScrollViewObserver class is declared to control the slide of other possible project components. The overall design concept is still the observer mode. An observer object is provided inside the class, and all components to be observed are added. When sliding, all registered components are notified to slide at the same time.
?? So who will act as the observer? According to the features of ListView, an object must be found externally, but the subitem cannot be used. In the current example, the best object is the floating header, because its structure is the same as that of each subitem, and there is always a need to slide together.
?? As a result, the overall structure is gradually clearer. The floating header is initialized outside the list. As the subscribed object, all list items (based on the reuse mechanism, there are usually a few or a dozen items) as the observer object of the horizontal slide component registered by the subscriber to the floating header, the subsequent slide process is completely controlled by the header.
?? First, rewrite the ListView component and add the header display logic callback to it.

Public class AdjustIndicatorListView extends ListView implements OnScrollListener {private OnGroupIndicatorShowListener onGroupIndicatorShowListener; private int touchStatus; // private MotionPack; // event coordinate cache // enumeration of touch action types private static final int IDLE =-1; private static final int MOVING = 1; private static final int STANDBY = 0; private static final int VERTICAL = 2; private stat Ic final int HORIZONTAL = 3; public AdjustIndicatorListView (Context context) {super (context); initAttr ();} public AdjustIndicatorListView (Context context, AttributeSet attrs) {super (context, Context, attrs); initAttr ();} public attributes (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr); initAttr ();} private void initAttr () {touchStatus = IDLE; MotionPack = new MotionPack () ;}@ Override public boolean onInterceptTouchEvent (MotionEvent ev) {// TODO Auto-generated method stub int action = ev. getAction (); switch (action) {case MotionEvent. ACTION_DOWN: motionPack. startX = ev. getRawX (); motionPack. startY = ev. getRawY (); touchStatus = STANDBY; break; case MotionEvent. ACTION_MOVE: motionPack. endX = ev. getRawX (); motionPack. endY = ev. getRawY (); If (touchStatus = STANDBY) {touchStatus = MOVING;} break; case MotionEvent. ACTION_UP: touchStatus = IDLE; break; default: touchStatus = IDLE; break;} // determines whether the current user is being dragged horizontally or vertically, avoid sliding interruption if (touchStatus = MOVING) {if (Math. abs (motionPack. endX-motionPack. startX)> = Math. abs (motionPack. endY-motionPack. startY) {touchStatus = HORIZONTAL;} else {touchStatus = VERTICAL;} If (touchStatus = VERTICAL) {return true;} else if (touchStatus = HORIZONTAL) {return false;} else {return super. callback (ev) ;}@ Override public void onScrollStateChanged (AbsListView view, int scrollState) {//} @ Override public void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {boolean show; if (firstVisibleItem = 0) {I F (getChildAt (firstVisibleItem )! = Null) {if (getChildAt (firstVisibleItem ). getTop ()> 0) {show = false;} else {show = true ;}} else {show = true;} if (getFirstVisiblePosition () = 0 & getChildAt (0 )! = Null & getChildAt (0). getTop ()> 0) {show = false;} if (onGroupIndicatorShowListener! = Null) {onGroupIndicatorShowListener. onGroupIndicatorShow (show) ;}} public void setOnGroupIndicatorShowListener (OnGroupIndicatorShowListener onGroupIndicatorShowListener) {setOnScrollListener (this); this. listener = listener;} public interface onGroupIndicatorShowListener {void OnGroupIndicatorShow (boolean show);} private class MotionPack {public float startX; public float endX; public float startY; public float endY ;}}

?? Then, rewrite a LinearLayout component and let onInterceptTouchEvent return true to completely intercept all events. Put InnerHorizontalScrollView into it so that it cannot receive any events and can only be moved by subscribing to the sliding condition of the header.

public class InterceptLinearLayout extends LinearLayout {    public InterceptLinearLayout(Context context) {        super(context);    }    public InterceptLinearLayout(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    public InterceptLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return true;    }}

?? Finally, an event processing portal is required. You can simply set an onTouchListener for the subitem and hand it over to the header for processing each touch event.
?? The code used is as follows:
??OnScrollChangedListener to be set to the floating Header

class OnScrollListenerImpl implements InnerHorizontalScrollView.OnScrollChangedListener {    private InnerHorizontalScrollView hsv;    OnScrollListenerImpl(InnerHorizontalScrollView scrollView) {        this.hsv = scrollView;    }    @Override    public void onScrollChanged(int l, int t, int oldl, int oldt, int grp) {        this.hsv.scrollTo(l, t);    }}

??OnTouchListener to be set to the List itself

class ListTouchListener implements View.OnTouchListener {    private InnerHorizontalScrollView hsv;    ListTouchListener(InnerHorizontalScrollView scrollView) {        // TODO Auto-generated constructor stub        this.hsv = scrollView;    }    @Override    public boolean onTouch(View v, MotionEvent event) {        hsv.onTouchEvent(event);        return false;    }}

??The Adapter class required by ListView

class IndicatorAdapter extends BaseAdapter {    @Override    public int getCount() {        return indicatorDataList == null?0:indicatorDataList.size();    }    @Override    public Object getItem(int position) {        return indicatorDataList == null?null:indicatorDataList.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ItemHolder holder;        if(convertView == null) {            convertView = LayoutInflater.from(resContext).inflate(R.layout.layout_adlv_item, null);            holder = new ItemHolder();            holder.args = new ArrayList<>();            for(int i = 1; i < 10; i++) {                TextView tv = (TextView) convertView.findViewById(resContext.getResources().getIdentifier("tvArg_"+i, "id", resContext.getPackageName()));                holder.args.add(tv);            }            holder.hsv = (InnerHorizontalScrollView) convertView.findViewById(R.id.hsvItem);            holder.listener = new OnScrollListenerImpl(holder.hsv);            hsvContent.addOnScrollChangedListener(holder.listener);            holder.hsv.addOnScrollChangedListener(indicatorImp);            convertView.setFocusable(true);            convertView.setClickable(true);            convertView.setOnTouchListener(listTouchListener);            convertView.setTag(holder);        } else {            holder = (ItemHolder) convertView.getTag();        }        List
 
   contentData = (List
  
   ) getItem(position);        if(contentData != null) {            for(int i = 0; i < 9; i++) {                holder.args.get(i).setText(contentData.get(i));            }        }        return convertView;    }    class ItemHolder {        List
   
     args;        InnerHorizontalScrollView hsv;        OnScrollListenerImpl listener;    }}
   
  
 

??Main Code

View indicatorView;InnerHorizontalScrollView hsvContent;OnScrollListenerImpl indicatorImp;View listHeader;InnerHorizontalScrollView headerHsv;OnScrollListenerImpl headerImp;ListTouchListener listTouchListener;AdjustIndicatorListView lvContent;IndicatorAdapter indicatorAdapter;List
 
  > indicatorDataList;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    resContext = this;    indicatorView = findViewById(R.id.indicatorBar);    hsvContent = (InnerHorizontalScrollView)indicatorView.findViewById(R.id.hsvItem);    listTouchListener = new ListTouchListener(hsvContent);    indicatorView.setOnTouchListener(listTouchListener);    indicatorImp = new OnScrollListenerImpl(hsvContent);    hsvContent.addOnScrollChangedListener(indicatorImp);    lvContent = (AdjustIndicatorListView) findViewById(R.id.adlvContent);    lvContent.setOnGroupIndicatorShowListener(new AdjustIndicatorListView.OnGroupIndicatorShowListener() {        @Override        public void OnGroupIndicatorShow(boolean show) {            indicatorView.setVisibility(show?View.VISIBLE:View.GONE);        }    });    listHeader = LayoutInflater.from(resContext).inflate(R.layout.layout_adlv_item, null);    headerHsv = (InnerHorizontalScrollView) listHeader.findViewById(R.id.hsvItem);    headerImp = new OnScrollListenerImpl(headerHsv);    hsvContent.addOnScrollChangedListener(headerImp);    lvContent.addHeaderView(listHeader);}
 

?? At this point, the list of horizontal sliding is designed. The actual test shows that both schemes can achieve their respective goals. The second scheme is complicated, but flexible and can be used at any position in the list, you can also perform other operations during the sliding process.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.