In the next few articles, I will go to the instructor's blog "Implementation of the drop-down PinnedHeaderExpandableListView" in detail to learn the code of the great god and record it.
Source: http://blog.csdn.net/singwhatiwanna/article/details/25546871
Let's take a look at the final effect:
Create an activity_main.xml File
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"><com.example.testexpandablelistview.ui.StickyLayout android:id="@+id/sticky_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="0dp" android:orientation="vertical"> <LinearLayout android:id="@+id/header" android:layout_width="match_parent" android:layout_height="100dp" android:gravity="center" android:background="#78a524" android:orientation="vertical"> </LinearLayout> <LinearLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> </LinearLayout></com.example.testexpandablelistview.ui.StickyLayout></RelativeLayout>
The above StickyLayout class is our custom LinearLayout. The idea is actually very simple. First, get the header and content views in StickyLayout. The Code is as follows:
Private void initData () {// use the getIdentifier () method to conveniently obtain the specified resource ID under each application package. // See http://blog.sina.com.cn/s/blog_5da93c8f0100zlrx.htmlint headerId = getResources () for details (). getIdentifier ("header", "id", getContext (). getPackageName (); int contentId = getResources (). getIdentifier ("content", "id", getContext (). getPackageName (); if (headerId! = 0 & contentId! = 0) {mHeader = findViewById (headerId); mContent = findViewById (contentId); mOriginalHeaderHeight = mHeader. getMeasuredHeight (); mHeaderHeight = mOriginalHeaderHeight; // It is a distance, indicating that when moving, the hand must be greater than this distance to start moving the control. MTouchSlop = ViewConfiguration. get (getContext ()). getScaledTouchSlop (); Log. d (TAG, "mTouchSlop =" + mTouchSlop);} else {throw new NoSuchElementException ("Did your view with \" header \ "or \" content \ "exist? ");}}
Reprocess the screen listening Function
@ Overridepublic boolean onInterceptTouchEvent (MotionEvent event) {int intercepted = 0; int x = (int) event. getX (); int y = (int) event. getY (); switch (event. getAction () {case MotionEvent. ACTION_DOWN: mLastXIntercept = x; mLastYIntercept = y; mLastX = x; mLastY = y; intercepted = 0; break; case MotionEvent. ACTION_MOVE: int deltaX = x-mLastXIntercept; int deltaY = y-mLastYIntercept; if (mStatus = STATUS_EXPA NDED & deltaY <=-mTouchSlop) {intercepted = 1;} else if (mGiveUpTouchEventListener! = Null) {if (mGiveUpTouchEventListener. giveUpTouchEvent (event) & deltaY >=mtouchslop) {intercepted = 1 ;}} break; case MotionEvent. ACTION_UP: {intercepted = 0; mLastXIntercept = mLastYIntercept = 0; break;} default: break;} Log. d (TAG, "intercepted =" + intercepted); // if it is 1, true is returned and passed to the current onTouchEvent. If the value is 0, false is returned and is passed to the subcontrol return intercepted! = 0 ;}
OnInterceptTouchEvent is defined in ViewGroup and used to intercept gesture events. Each gesture event first calls onInterceptTouchEvent. If this method returns true, the event is intercepted and the current onTouchEvent is triggered, if false is returned, it is passed to the Child control.
@ Overridepublic boolean onTouchEvent (MotionEvent event) {int x = (int) event. getX (); int y = (int) event. getY (); Log. d (TAG, "x =" + x + "y =" + y + "mlastY =" + mLastY); switch (event. getAction () {case MotionEvent. ACTION_DOWN: break; case MotionEvent. ACTION_MOVE: int deltaX = x-mLastX; int deltaY = y-mLastY; Log. d (TAG, "mHeaderHeight =" + mHeaderHeight + "deltaY =" + deltaY + "mlastY =" + mLastY); mHeaderHeight + = deltaY; setHeaderHeight (mHeaderHeight); break; case MotionEvent. ACTION_UP: int destHeight = 0; if (mHeaderHeight <= required * 0.5) {destHeight = 0; mStatus = STATUS_COLLAPSED;} else {destHeight = mOriginalHeaderHeight; mStatus = STATUS_EXPANDED ;} // slide slowly toward the end this. smoothSetHeaderHeight (mHeaderHeight, destHeight, 500); break; default: break;} mLastX = x; mLastY = y; return true ;}
Send the event to onTouchEvent when sliding
In the slide event, setHeaderHeight changes the height of the header part above. When it is lifted, it determines whether the original height is changed, and then slowly slides to the end point.
/** Change the header height */private void setHeaderHeight (int height) {if (height <0) {height = 0;} else if (height> mOriginalHeaderHeight) {height = mOriginalHeaderHeight;} if (mHeaderHeight! = Height | true) {mHeaderHeight = height; mHeader. getLayoutParams (). height = mHeaderHeight; mHeader. requestLayout ();}}
public void smoothSetHeaderHeight(final int from, final int to, long duration) {final int frameCount = (int) (duration / 1000f * 30) + 1;final float partation = (to - from) / (float) frameCount;new Thread("Thread#smoothSetHeaderHeight") {public void ruan(){for(int i = 0; i < frameCount; i++) {final int height;if(i == frameCount - 1){height = to;}else{height = (int)(from + partation * i);}post(new Runnable() {@Overridepublic void run() {setHeaderHeight(height);}});try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}}.start();}
The above View. post (Runnable) method is used to add the Runnable object to the UI thread for running, thus changing the height of the header part.
The complete code of the StickyLayout class is as follows:
Package com. example. testexpandablelistview. ui; import java. util. noSuchElementException; import android. annotation. targetApi; import android. content. context; import android. OS. build; import android. util. attributeSet; import android. util. log; import android. view. motionEvent; import android. view. view; import android. view. viewConfiguration; import android. widget. linearLayout;/*** custom LinearLayout * @ author