Specific needs 1. Make a system-level suspension button, just like the effect of the suspension button on the desktop of the iPhone, which can be dragged at will, and the suspension button will automatically pull aside as soon as the hand is released. 2. It can be clicked and dragged at will. 3. When the suspension button comes to the edge automatically, or when it moves to the edge, it hides the half automatically. 4. Both horizontal and vertical screen switching are compatible 1. Add View to Windows Manager, which is implemented by custom controls. 2. In the MotionEvent.ACTION_MOVE event in onTouch, the movement is achieved by controlling the specific coordinates of the suspension button. 3. In the MotionEvent.ACTION_UP event in onTouch, the suspension button is controlled to automatically pull aside and hide half of the button. But here the onTouch and onClick events are triggered together, but there is also a solution. You can decide whether to trigger the click event or not at the moment when your hand is open, by the distance of movement. If you return to false, the trigger point will be triggered. Click event, if true is returned, the click event will be triggered 4. Capturing horizontal and vertical screen switching events by using the custom control onLayout method. 5. There is also a question of which side to park on, which side to park closer to by coordinates. It's on the right side. (http://img.blog.csdn.net/20170316151428650? Watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZQvSHVhbmdUaWVCaW5n/font/5a6L5T/fonize/400/fill/I0JBQkFCMA=/dissolve/70/gravity/East)
The following is the specific implementation code:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import com.iapppay.openid.channel.LoginResultCallback;
import com.iapppay.openid.channel.OpenIDApplication;
import com.iapppay.openid.channel.util.DisplayUtil;
import com.iapppay.openid.channel.util.LogUtil;
import com.iapppay.openid.channel.util.Res;
/**
* Created by HuangTiebing 2017/2/14.
*/
public class DragFloatActionButton extends ImageView implements View.OnTouchListener, View.OnClickListener {
public static String TAG = "DragFloatActionButton";
private Context context;
float lastX, lastY;
float originX, originY;
int screenWidth;
int screenHeight;
private int originWidth;
private WindowManager windowManager;
// // This Windows Manager Params variable is the acquired global variable to hold the properties of the suspended window.
private WindowManager.LayoutParams windowManagerParams;
private LoginResultCallback resultCallback; //Suspension button click callback
public DragFloatActionButton(Context context, boolean isForceLogin, LoginResultCallback resultCallback) {
this(context, null);
OpenIDApplication.getInstance().setForceLogin(isForceLogin);
this.resultCallback = resultCallback;
}
public DragFloatActionButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
Point screenSize = DisplayUtil.getScreenSize(context);
screenWidth = screenSize.x;
screenHeight = screenSize.y;
setImageResource(Res.drawable(context, "ipay_float_btn_bg"));
setOnTouchListener(this);
setOnClickListener(this);
windowManager = (WindowManager) getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
}
public int getOriginWidth() {
return originWidth;
}
public void setOriginWidth(int originWidth) {
this.originWidth = originWidth;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
windowManagerParams = (WindowManager.LayoutParams) this.getLayoutParams();
//Get the height of the status bar
Rect frame = new Rect();
getWindowVisibleDisplayFrame(frame);
int ea = event.getAction();
switch (ea) {
case MotionEvent.ACTION_DOWN:
lastX = event.getRawX();// Get the original X coordinates of the touch position of the touch event
lastY = event.getRawY();
originX = lastX;
originY = lastY;
break;
case MotionEvent.ACTION_MOVE:
float dx = event.getRawX() - lastX;
float dy = event.getRawY() - lastY;
windowManagerParams.x += dx;
windowManagerParams.y += dy;
LogUtil.d(TAG, "Moving distance: dx=" + dx + ",dy=" + dy);
showAllBtn();
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
float lastMoveDx = Math.abs(event.getRawX() - originX);
float lastMoveDy = Math.abs(event.getRawY() - originY);
LogUtil.d(TAG, "When loosened, move distance: lastMoveDx=" + lastMoveDx + ", lastMoveDy=" + lastMoveDy);
if (lastMoveDx < 10 && lastMoveDy < 10) { //If the distance is too small, it will be regarded as a click.
return false;
} else {
updateViewLayout(event);
isFirstClick = true;
return true;
}
}
return false;
}
/**
* Display the entire Icon
*/
public void showAllBtn() {
windowManagerParams.width = originWidth;
windowManagerParams.height = originWidth;
setImageResource(Res.drawable(context, "ipay_float_btn_bg"));
windowManager.updateViewLayout(this, windowManagerParams); // Refresh display
}
/**
* The suspension button appears on the left
*/
private void showInLeft() {
windowManagerParams.x = 0;
windowManagerParams.width = originWidth / 2;
windowManagerParams.height = originWidth;
setImageResource(Res.drawable(context, "ipay_float_btn_left_hidden"));
windowManager.updateViewLayout(this, windowManagerParams); // Refresh display
}
/**
* The suspension button is displayed on the right.
*/
private void showInRight() {
windowManagerParams.width = originWidth / 2;
windowManagerParams.height = originWidth;
windowManagerParams.x = screenWidth - windowManagerParams.width;
setImageResource(Res.drawable(context, "ipay_float_btn_right_hidden"));
windowManager.updateViewLayout(this, windowManagerParams); // Refresh display
}
/**
* The suspension button is displayed on it.
*/
private void showInTop() {
windowManagerParams.y = 0;
windowManagerParams.width = originWidth;
windowManagerParams.height = originWidth / 2;
setImageResource(Res.drawable(context, "ipay_float_btn_top_hidden"));
windowManager.updateViewLayout(this, windowManagerParams); // Refresh display
}
/**
* The suspension button is displayed below.
*/
private void showInBottom() {
windowManagerParams.width = originWidth;
windowManagerParams.height = originWidth / 2;
windowManagerParams.y = screenHeight - windowManagerParams.width;
setImageResource(Res.drawable(context, "ipay_float_btn_bottom_hidden"));
windowManager.updateViewLayout(this, windowManagerParams); // Refresh display
}
/**
* Update the suspension Icon
*
* @param event Manual Mobile Events
*/
public void updateViewLayout(MotionEvent event) {
Point center = new Point(screenWidth / 2, screenHeight / 2); //Screen Center
float xOffset, yOffset;//The offset on X-axis and Y-axis with the center of the screen as the origin
if (event != null) {//Manual Mobile
xOffset = event.getRawX() - center.x;
yOffset = event.getRawY() - center.y;
} else {//Automatic hiding
xOffset = lastX - center.x;
yOffset = lastY - center.y;
}
if (Math.abs(xOffset) >= Math.abs(yOffset)) {//Indent left or right to hide
if (xOffset <= 0) { //Indent to the left
showInLeft();
} else {
showInRight();
}
} else {//Up or down indentation hiding
if (yOffset <= 0) {//Retract upward
showInTop();
} else {
showInBottom();
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Point screenSize = DisplayUtil.getScreenSize(context);
if (screenWidth != screenSize.x) {//Screen Rotation Switching
screenWidth = screenSize.x;
screenHeight = screenSize.y;
lastY = windowManagerParams.x;
lastX = windowManagerParams.y;
windowManagerParams.x = (int) lastX;
windowManagerParams.y = (int) lastY;
updateViewLayout(null);
}
}
private boolean isFirstClick = true;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public void onClick(View v) {
LogUtil.d(TAG, "Execute click events");
if (!isFirstClick) {
OpenIDApplication.getInstance().floatBtnClick(context, OpenIDApplication.getInstance().isForceLogin(), resultCallback);
} else {//Semi-hidden status, Click to display all
isFirstClick = false;
showAllBtn();
}
}
}
Call the implementation code, note here that there is a problem, pop-up system-level suspension window, need to configure permissions:
And android 6.0 mobile phones, but also pop-up dialog box to ask whether the user is running, if the user refused, it can not pop up the system-level suspension window, there are individual mobile phone manufacturers modified the android source code, but also need to enter the system settings to allow the application to pop up the suspension window. In this way, the experience is very bad, but here's a trick. Setting to toast type as follows completely solves the problem, neither configuring permissions nor popping up windows to obtain permissions from users.
WindowManager.LayoutParams windowManagerParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_TOAST,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
The specific implementation code is as follows:
DragFloatActionButton floatBtn = new DragFloatActionButton(context, isForceLogin, mResultCallback);
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// Setting LayoutParams (Global Variable) Related Parameters
WindowManager.LayoutParams windowManagerParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_TOAST,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
/**
* Note that the value of flag can be:
* The effect of the flags attribute below is the same as "lock".
* The suspension window is untouchable, does not accept any event, and does not affect the subsequent event response.
* LayoutParams.FLAG_NOT_TOUCH_MODAL It does not affect subsequent events.
* LayoutParams.FLAG_NOT_FOCUSABLE Non focusing
* LayoutParams.FLAG_NOT_TOUCHABLE Impossible to touch
*/
// Adjust the suspension window to the upper left corner for easy adjustment of coordinates
windowManagerParams.gravity = Gravity.LEFT | Gravity.TOP;
// Starting at the top left corner of the screen, setx,yinitial value
windowManagerParams.x = 0;
windowManagerParams.y = 0;
// Setting Length and Width Data of Suspension Window
floatBtn.measure(0, 0);
floatBtn.setOriginWidth(floatBtn.getMeasuredWidth() - 50);
windowManagerParams.width = floatBtn.getOriginWidth();
windowManagerParams.height = windowManagerParams.width;
// Display myFloatView image
windowManager.addView(floatBtn, windowManagerParams);