Android ScrollView monitoring

Keywords: Android Mobile xml Windows

With the rapid development of the mobile internet, it has been closely related to our lives. Many people can be seen in the bus and subway looking down at their mobile phone screens. From then on, the word "bowing tribe" came into being. As a developer of the mobile industry, I am also a "bowing tribe". I read the news on the bus and subway to pass off my work time. Time, sometimes also look at some of the interface effects of popular apps, why are people's apps so popular? User experience is also directly related to UI design. Recently, I saw the following effects in App, which was commented by American Troupe and the public. I feel that the users are good and human, so I try to achieve it myself. Then I will explain how to achieve it.

As we can see in the figure (2) above, when the snap-up layout slides upward to the navigation bar layout, the snap-up layout is pasted under the navigation bar layout immediately. The other layout below can still slide. When we slide downward, the snap-up layout slides downward again. It seems a little complicated, but when you say the idea, you may suddenly realize it.

When we slide up, we judge whether the layout of the snap-up immediately slides under the navigation bar layout. If the top of the snap-up immediately reaches the navigation bar, we create a new suspension frame to display under the navigation bar, which achieves the effect of snapping-up immediately under the navigation bar. When we slide down, we snap-up the layout immediately. The following is just below the newly built instant purchase suspension frame, we remove the instant purchase suspension frame, which may be a bit awkward. Now that we know the idea, we will achieve the effect next.

Create a new Android project named MeiTuanDemo. First look at the layout of buy_layout.xml. Here, for convenience, I cut the pictures directly from the group.


<?xml version="1.0" encoding="UTF-8"?><LinearLayout xmlns:android=""    android:orientation="horizontal"    android:layout_width="fill_parent"    android:layout_height="wrap_content" >    <ImageView        android:id="@+id/buy_layout"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:background="@drawable/buy" /></LinearLayout>

The layout of the snap-up is realized immediately, and then the layout of the main interface is realized. The layout of the navigation bar is above. For convenience or directly intercepted pictures from the beauty group, then the layout of the ViewPager is below. The layout of the snap-up is immediately realized. The other layout is placed in ScrollView. The interface is still very simple.
<LinearLayout xmlns:android=""    xmlns:tools=""    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"  >      <ImageView        android:id="@+id/imageView1"        android:scaleType="centerCrop"        android:layout_width="match_parent"        android:layout_height="45dip"        android:src="@drawable/navigation_bar" />            <com.example.meituandemo.MyScrollView        android:id="@+id/scrollView"        android:layout_width="fill_parent"        android:layout_height="fill_parent" >        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="vertical" >            <ImageView                android:id="@+id/iamge"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:background="@drawable/pic"                android:scaleType="centerCrop" />            <include                android:id="@+id/buy"                layout="@layout/buy_layout" />            <ImageView                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:background="@drawable/one"                android:scaleType="centerCrop" />            <ImageView                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:background="@drawable/one"                android:scaleType="centerCrop" />            <ImageView                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:background="@drawable/one"                android:scaleType="centerCrop" />        </LinearLayout>    </com.example.meituandemo.MyScrollView></LinearLayout>

You will find that the main interface layout above is not ScrollView, but a custom MyScrollView. Next, look at the code in the MyScrollView class.


package com.example.meituandemo;import android.content.Context;import android.os.Handler;import android.util.AttributeSet;import android.view.MotionEvent;import android.widget.ScrollView;/** * Blog address:** @author xiaanming * */public class MyScrollView extends ScrollView private OnScrollListener onScrollListener; /**  * It's mainly used when the user's finger is away from MyScrollView. MyScrollView is still sliding. We use it to save the distance of Y and then compare it. */ private int lastScrollY;  public MyScrollView(Context context) {  this(context, null); }  public MyScrollView(Context context, AttributeSet attrs) {  this(context, attrs, 0); } public MyScrollView(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle); }  /**  * Setting up scroll interface* @param onScrollListener  */ public void setOnScrollListener(OnScrollListener onScrollListener) {  this.onScrollListener = onScrollListener; } /**  * Used to get the Y-distance of the MyScrollView scroll when the user's finger leaves MyScrollView, and then call back to the onScroll method */ private Handler handler = new Handler() {  public void handleMessage(android.os.Message msg) {   int scrollY = MyScrollView.this.getScrollY();      //At this time, the distance is not equal to the recorded distance, sending messages to handler every 5 milliseconds.   if(lastScrollY != scrollY){    lastScrollY = scrollY;    handler.sendMessageDelayed(handler.obtainMessage(), 5);     }   if(onScrollListener != null){    onScrollListener.onScroll(scrollY);   }     }; };  /**  * Rewrite onTouchEvent. When the user's hand is on MyScrollView, * directly calls back the Y-direction distance of MyScrollView sliding to onScroll method. When the user raises his hand, * MyScrollView may still be sliding, so when the user raises his hand, we send messages to handler every 5 milliseconds and process the sliding distance of MyScrollView in handler. */ @Override public boolean onTouchEvent(MotionEvent ev) {  if(onScrollListener != null){   onScrollListener.onScroll(lastScrollY = this.getScrollY());  }  switch(ev.getAction()){  case MotionEvent.ACTION_UP:          handler.sendMessageDelayed(handler.obtainMessage(), 5);     break;  }  return super.onTouchEvent(ev); } /**  *   * Rolling callback interface** @author xiaanming  *  */ public interface OnScrollListener{  /**   * Callback method to return the Y-direction distance of MyScrollView sliding* @param scrollY   *     ,   */  public void onScroll(int scrollY); }  }
Looking at the code, you may understand that the ScrollView scroll Y value is monitored. We know that ScrollView does not achieve scroll monitoring, so we have to monitor ScrollView by ourselves. We naturally think of implementing scroll Y axis monitoring in onTouchEvent() method, but you will find that when we slide ScrollView, when our fingers are away. Open ScrollView. It may continue to slide for a long distance, so we choose to judge whether ScrollView stops sliding every five milliseconds when the user's finger leaves, and call back the ScrollView's scroll Y value to the onScroll(int scrollY) method of the OnScrollListener interface. We only need to call ScrollView and we only need to call setOnScrollListener method on ScrollView to listen. Scroll the Y value.

Realized to monitor the Y value of ScrollView scroll, and then it's simple. We just need to show that we can snap up the suspension box immediately and remove the suspension box. Next, we'll look at the code of the main interface Activity.


package com.example.meituandemo;import;import android.content.Context;import;import android.os.Bundle;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.WindowManager;import android.view.WindowManager.LayoutParams;import android.widget.LinearLayout;import com.example.meituandemo.MyScrollView.OnScrollListener;/** * Blog address:** @author xiaanming * */public class MainActivity extends Activity implements OnScrollListenerprivate MyScrollView myScrollView; private LinearLayout mBuyLayout; private WindowManager mWindowManager; /**  * Mobile screen width */ private int screenWidth; /**  * Suspension Frame View */ private static View suspendView; /**  * Parameters of suspension frame */ private static WindowManager.LayoutParams suspendLayoutParams; /**  * The height of the purchase layout */ private int buyLayoutHeight; /**  * myScrollView Distance from the top of its parent layout */ private int myScrollViewTop; /**  * The top distance between the purchase layout and its parent layout */ private int buyLayoutTop;  @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);    myScrollView = (MyScrollView) findViewById(;  mBuyLayout = (LinearLayout) findViewById(;    myScrollView.setOnScrollListener(this);  mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);  screenWidth = mWindowManager.getDefaultDisplay().getWidth();   } /**  * When the window is focused, that is, when all the layouts are drawn, we get the height of the purchased layout and the top position of the myScrollView distance from the parent layout. */ @Override   public void onWindowFocusChanged(boolean hasFocus) {       super.onWindowFocusChanged(hasFocus);       if(hasFocus){      buyLayoutHeight = mBuyLayout.getHeight();      buyLayoutTop = mBuyLayout.getTop();            myScrollViewTop = myScrollView.getTop();     } }  /**  * Rolling callback method, when the rolling Y distance is greater or equal to the purchase layout distance from the top of the parent layout, the purchase suspension box is displayed * When the rolling Y distance is less than the purchase layout distance from the top of the parent layout and the height of the purchase layout, the purchase suspension box is removed.* */ @Override public void onScroll(int scrollY) {  if(scrollY >= buyLayoutTop){   if(suspendView == null){    showSuspend();   }  }else if(scrollY <= buyLayoutTop + buyLayoutHeight){   if(suspendView != null){    removeSuspend();   }  } } /**  * Show the purchased suspension box */ private void showSuspend(){  if(suspendView == null){   suspendView = LayoutInflater.from(this).inflate(R.layout.buy_layout, null);   if(suspendLayoutParams == null){    suspendLayoutParams = new LayoutParams();    suspendLayoutParams.type = LayoutParams.TYPE_PHONE; //The type of suspension window, usually set to 2002, is above all applications, but below the status bar.     suspendLayoutParams.format = PixelFormat.RGBA_8888;     suspendLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL                        | LayoutParams.FLAG_NOT_FOCUSABLE;  //The behavior of suspended windows, such as unfocusable, modeless dialog boxes, etc.     suspendLayoutParams.gravity = Gravity.TOP;  //Alignment of suspension windows    suspendLayoutParams.width = screenWidth;    suspendLayoutParams.height = buyLayoutHeight;      suspendLayoutParams.x = 0//Location of suspension window X    suspendLayoutParams.y = myScrollViewTop;  //// Position of suspension window Y   }  }    mWindowManager.addView(suspendView, suspendLayoutParams); }   /**  * Remove the purchased suspension box */ private void removeSuspend(){  if(suspendView != null){   mWindowManager.removeView(suspendView);   suspendView = null;  } }}

The above code is relatively simple. According to the sliding distance of ScrollView, the display and removal of the suspension frame are judged. The implementation of the suspension frame is mainly realized through the class of Windows Manager. Calling the addView method of this class is used to add a suspension frame, and removeView is used to remove the suspension frame.
Through the above code, we can achieve the effect of American Mission and public comment. Before running the project, we must add <uses-permission and roid: name="android.permission.SYSTEM_ALERT_WINDOW"/>in Android Manifest.xml. <uses-permission and roid:name="android.permission.SYSTEM_ALERT_WINDOW"/>


Let's run the project and see how it works.


Okay, that's the end of today's lecture. If you have any questions, please leave a message below.

Project source code, click download

PS: If you are interested, you can take a look at it. Android Aesthetic Group Network, Revised Version of Buying Frame Suspension Effect



Posted by jburfield on Mon, 22 Apr 2019 22:30:36 -0700