Implementation Method of horizontal sliding listview effect, scrollview nested horizontal sliding listview lagging solution, listviewscrollview
Most of the time, the page needs to achieve the listview Effect of horizontal sliding. There is a way on the network to customize the HorizontalListView, the usage is the same as the normal listview, you can achieve horizontal sliding effect.
However, if a horizontal sliding listview is embedded in a scrollview with vertical sliding on the interface, sliding horizontal listview will become very slow. I recently encountered such a problem. I have been keeping my mind in listening for horizontal and vertical sliding gestures. The vertical scrollview sliding effect is forbidden when the sliding angle is smaller than 45. But it has not been studied.
As a coincidence, the light flashed and thought of embedding the gridview with HorizontalScrollView to achieve horizontal sliding. Really great. There is no choppy phenomenon.
The method is as follows:
Layout:
<HorizontalScrollView
Android: layout_width = "fill_parent"
Android: layout_height = "wrap_content"
Android: scrollbars = "none">
<LinearLayout
Android: layout_width = "wrap_content"
Android: layout_height = "wrap_content"
Android: orientation = "horizontal">
<GridView
Android: id = "@ + id/server_details_content_view_product_gv"
Android: layout_width = "wrap_content"
Android: layout_height = "wrap_content">
</GridView>
</LinearLayout>
</HorizontalScrollView>
Set the properties of the gridview in the Code. Otherwise, the sliding effect is not displayed.
/** Set the GirdView parameter. The length generally ranges from 100 to 230. Set the adaption. Size is the size of the list */
Private void setGridView (GridView gv, int length, int size ){
DisplayMetrics dm = new DisplayMetrics ();
GetWindowManager (). getDefaultDisplay (). getMetrics (dm );
Float density = dm. density;
Int gridviewWidth = (int) (size * (length + 4) * density );
Int itemWidth = (int) (length * density );
LinearLayout. LayoutParams params = new LinearLayout. LayoutParams (
GridviewWidth, LinearLayout. LayoutParams. FILL_PARENT );
Gv. setLayoutParams (params); // sets the GirdView layout parameter, which is the key to horizontal layout.
Gv. setColumnWidth (itemWidth); // you can specify the itemWidth of a list.
Gv. setHorizontalSpacing (5); // sets the horizontal spacing of list items.
Gv. setStretchMode (GridView. NO_STRETCH );
Gv. setNumColumns (size); // set the number of columns = the number of list sets
}
When setting the adapter. The adapter is written in the same way as the normal gridview adapter, and no code is attached again. If you have any questions, leave a message.
SetGridView (vStepsGv, 230, serviceContentList. size ());
StepsAdapter = new ServerStepsListAdapter (this, serviceContentList );
VStepsGv. setAdapter (stepsAdapter );
In addition, if you do not need scrollview with vertical sliding of the outer layer, this custom listview is still good! Code: (The usage is the same as that of the normal listview. If you have any questions, leave a message)
/**
* Left-right sliding listview
*
* @ Author lunizhu
*
*/
Public class HorizontalListView extends AdapterView <ListAdapter> {
Public boolean mAlwaysOverrideTouch = true;
Protected ListAdapter mAdapter;
Private int mLeftViewIndex =-1;
Private int mRightViewIndex = 0;
Protected int mCurrentX;
Protected int mNextX;
Private int mMaxX = Integer. MAX_VALUE;
Private int mDisplayOffset = 0;
Protected Scroller mScroller;
Private GestureDetector mGesture;
Private Queue <View> mRemovedViewQueue = new Queue list <View> ();
Private OnItemSelectedListener mOnItemSelected;
Private OnItemClickListener mOnItemClicked;
Private OnItemLongClickListener mOnItemLongClicked;
Private boolean mDataChanged = false;
Public HorizontalListView (Context context, AttributeSet attrs ){
Super (context, attrs );
InitView ();
}
Private synchronized void initView (){
MLeftViewIndex =-1;
MRightViewIndex = 0;
MDisplayOffset = 0;
MCurrentX = 0;
MNextX = 0;
MMaxX = Integer. MAX_VALUE;
MScroller = new Scroller (getContext ());
MGesture = new GestureDetector (getContext (), mOnGesture );
}
@ Override
Public void setOnItemSelectedListener (
AdapterView. OnItemSelectedListener listener ){
MOnItemSelected = listener;
}
@ Override
Public void setOnItemClickListener (AdapterView. OnItemClickListener listener ){
MOnItemClicked = listener;
}
@ Override
Public void setOnItemLongClickListener (
AdapterView. OnItemLongClickListener listener ){
MOnItemLongClicked = listener;
}
Private DataSetObserver mDataObserver = new DataSetObserver (){
@ Override
Public void onChanged (){
Synchronized (HorizontalListView. this ){
MDataChanged = true;
}
Invalidate ();
RequestLayout ();
}
@ Override
Public void onInvalidated (){
Reset ();
Invalidate ();
RequestLayout ();
}
};
@ Override
Public ListAdapter getAdapter (){
Return mAdapter;
}
@ Override
Public View getSelectedView (){
// TODO: implement
Return null;
}
@ Override
Public void setAdapter (ListAdapter adapter ){
If (mAdapter! = Null ){
MAdapter. unregisterDataSetObserver (mDataObserver );
}
MAdapter = adapter;
MAdapter. registerDataSetObserver (mDataObserver );
Reset ();
}
Private synchronized void reset (){
InitView ();
RemoveAllViewsInLayout ();
RequestLayout ();
}
@ Override
Public void setSelection (int position ){
Int positionX = position * this. getWidth ();
Int maxWidth = this. getChildCount () * this. getWidth ();
If (positionX <= 0 ){
PositionX = 0;
}
If (positionX> maxWidth ){
PositionX = maxWidth;
}
ScrollTo (positionX );
}
Private void addAndMeasureChild (final View child, int viewPos ){
LayoutParams params = child. getLayoutParams ();
If (params = null ){
Params = new LayoutParams (LayoutParams. FILL_PARENT,
LayoutParams. FILL_PARENT );
}
AddViewInLayout (child, viewPos, params, true );
Child. measure (
MeasureSpec. makeMeasureSpec (getWidth (), MeasureSpec. AT_MOST ),
MeasureSpec. makeMeasureSpec (getHeight (), MeasureSpec. AT_MOST ));
}
@ Override
Protected synchronized void onLayout (boolean changed, int left, int top,
Int right, int bottom ){
Super. onLayout (changed, left, top, right, bottom );
If (mAdapter = null ){
Return;
}
If (mDataChanged ){
Int oldCurrentX = mCurrentX;
InitView ();
RemoveAllViewsInLayout ();
MNextX = oldCurrentX;
MDataChanged = false;
}
If (mScroller. computescroloffset ()){
Int scrollx = mScroller. getCurrX ();
MNextX = scrollx;
}
If (mNextX <= 0 ){
MNextX = 0;
MScroller. forceFinished (true );
}
If (mNextX> = mMaxX ){
MNextX = mMaxX;
MScroller. forceFinished (true );
}
Int dx = mCurrentX-mNextX;
RemoveNonVisibleItems (dx );
FillList (dx );
PositionItems (dx );
MCurrentX = mNextX;
If (! MScroller. isFinished ()){
Post (new Runnable (){
@ Override
Public void run (){
RequestLayout ();
}
});
}
}
Private void fillList (final int dx ){
Int edge = 0;
View child = getChildAt (getChildCount ()-1 );
If (child! = Null ){
Edge = child. getRight ();
}
FillListRight (edge, dx );
Edge = 0;
Child = getChildAt (0 );
If (child! = Null ){
Edge = child. getLeft ();
}
FillListLeft (edge, dx );
}
Private void fillListRight (int rightEdge, final int dx ){
While (rightEdge + dx <getWidth ()
& MRightViewIndex <mAdapter. getCount ()){
View child = mAdapter. getView (mRightViewIndex,
MRemovedViewQueue. poll (), this );
AddAndMeasureChild (child,-1 );
RightEdge + = child. getMeasuredWidth ();
If (mRightViewIndex = mAdapter. getCount ()-1 ){
MMaxX = mCurrentX + rightEdge-getWidth ();
}
If (mMaxX <0 ){
MMaxX = 0;
}
MRightViewIndex ++;
}
}
Private void fillListLeft (int leftEdge, final int dx ){
While (leftEdge + dx> 0 & mLeftViewIndex> = 0 ){
View child = mAdapter. getView (mLeftViewIndex,
MRemovedViewQueue. poll (), this );
AddAndMeasureChild (child, 0 );
LeftEdge-= child. getMeasuredWidth ();
MLeftViewIndex --;
MDisplayOffset-= child. getMeasuredWidth ();
}
}
Private void removeNonVisibleItems (final int dx ){
View child = getChildAt (0 );
While (child! = Null & child. getRight () + dx <= 0 ){
MDisplayOffset + = child. getMeasuredWidth ();
MRemovedViewQueue. offer (child );
RemoveViewInLayout (child );
MLeftViewIndex ++;
Child = getChildAt (0 );
}
Child = getChildAt (getChildCount ()-1 );
While (child! = Null & child. getLeft () + dx> = getWidth ()){
MRemovedViewQueue. offer (child );
RemoveViewInLayout (child );
MRightViewIndex --;
Child = getChildAt (getChildCount ()-1 );
}
}
Private void positionItems (final int dx ){
If (getChildCount ()> 0 ){
MDisplayOffset + = dx;
Int left = mDisplayOffset;
For (int I = 0; I <getChildCount (); I ++ ){
View child = getChildAt (I );
Int childWidth = child. getMeasuredWidth ();
Child. layout (left, 0, left + childWidth,
Child. getMeasuredHeight ());
Left + = childWidth + child. getPaddingRight ();
}
}
}
Public synchronized void scrollTo (int x ){
Mscroroller. startScroll (mNextX, 0, x-mNextX, 0 );
RequestLayout ();
}
@ Override
Public boolean dispatchTouchEvent (MotionEvent ev ){
Boolean handled = super. dispatchTouchEvent (ev );
Handled | = mGesture. onTouchEvent (ev );
Return handled;
}
Protected boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX,
Float velocityY ){
Synchronized (HorizontalListView. this ){
MScroller. fling (mNextX, 0, (int)-velocityX, 0, 0, mMaxX, 0, 0 );
}
RequestLayout ();
Return true;
}
Protected boolean onDown (MotionEvent e ){
MScroller. forceFinished (true );
Return true;
}
Private OnGestureListener mOnGesture = new GestureDetector. SimpleOnGestureListener (){
@ Override
Public boolean onDown (MotionEvent e ){
Return HorizontalListView. this. onDown (e );
}
@ Override
Public boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX,
Float velocityY ){
Return HorizontalListView. this
. OnFling (e1, e2, velocityX, velocityY );
}
@ Override
Public boolean onScroll (MotionEvent e1, MotionEvent e2,
Float distanceX, float distanceY ){
Synchronized (HorizontalListView. this ){
MNextX + = (int) distanceX;
}
RequestLayout ();
Return true;
}
@ Override
Public boolean onSingleTapConfirmed (MotionEvent e ){
For (int I = 0; I <getChildCount (); I ++ ){
View child = getChildAt (I );
If (isEventWithinView (e, child )){
If (mOnItemClicked! = Null ){
MOnItemClicked. onItemClick (HorizontalListView. this,
Child, mLeftViewIndex + 1 + I,
MAdapter. getItemId (mLeftViewIndex + 1 + I ));
}
If (mOnItemSelected! = Null ){
MOnItemSelected. onItemSelected (HorizontalListView. this,
Child, mLeftViewIndex + 1 + I,
MAdapter. getItemId (mLeftViewIndex + 1 + I ));
}
Break;
}
}
Return true;
}
@ Override
Public void onLongPress (MotionEvent e ){
Int childCount = getChildCount ();
For (int I = 0; I <childCount; I ++ ){
View child = getChildAt (I );
If (isEventWithinView (e, child )){
If (mOnItemLongClicked! = Null ){
MOnItemLongClicked. onItemLongClick (
HorizontalListView. this, child, mLeftViewIndex
+ 1 + I,
MAdapter. getItemId (mLeftViewIndex + 1 + I ));
}
Break;
}
}
}
Private boolean isEventWithinView (MotionEvent e, View child ){
Rect viewRect = new Rect ();
Int [] childPosition = new int [2];
Child. getLocationOnScreen (childPosition );
Int left = childPosition [0];
Int right = left + child. getWidth ();
Int top = childPosition [1];
Int bottom = top + child. getHeight ();
ViewRect. set (left, top, right, bottom );
Return viewRect. contains (int) e. getRawX (), (int) e. getRawY ());
}
};
}