Android's activity-based floating ball implementation, no need to apply for floating frame permissions, suitable for display on the game homepage

  • Generally, when you access the channel SDK, there will be a floating ball in their SDK, and it will float on your application. When you click on the floating ball, the menu bar, game center, user center and other pages will pop up. Some SDK implementations need to apply for permission. If the user does not give permission, the floating ball function will not be available. This method is definitely not acceptable. Next, we will implement a floating ball attached to the Activity page.
  • First of all, we need to customize a View, which can inherit ImageView or other Views, and then re-onMeasure, onDraw, onTouchEvent and other methods to realize the logic of dragging
    public class DragView extends ImageView {
        private float downX, downY;
        private int width, height;
        private final int screenWidth, screenHeight;
        private int l, t, r, b;
        boolean isDoLayout = false;
        private boolean isDrag = false;
    
        private OnClickCallback onClickCallback;
    
        public interface OnClickCallback {
            void onClick(View v);
        }
    
        public DragView(Context context, AttributeSet attrs) {
            super(context, attrs);
            screenWidth = context.getResources().getDisplayMetrics().widthPixels;
            screenHeight = context.getResources().getDisplayMetrics().heightPixels - getStatusBarHeight();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            width = getMeasuredWidth();
            height = getMeasuredHeight();
        }
    
        public int getStatusBarHeight() {
            int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
            return getResources().getDimensionPixelSize(resourceId);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (isDoLayout) {
                doLayout(l, t, r, b);
            }
        }
    
        public void doLayout(int l, int t, int r, int b) {
            isDoLayout = true;
            this.l = l;
            this.t = t;
            this.r = r;
            this.b = b;
            this.layout(l, t, r, b);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
            if (this.isEnabled()) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        isDrag = false;
                        downX = event.getX();
                        downY = event.getY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        final float xDistance = event.getX() - downX;
                        final float yDistance = event.getY() - downY;
                        int l, r, t, b;
                        if (Math.abs(xDistance) > 10 || Math.abs(yDistance) > 10) {
                            isDrag = true;
                            l = (int) (getLeft() + xDistance);
                            r = l + width;
                            t = (int) (getTop() + yDistance);
                            b = t + height;
                            if (l < 0) {
                                l = 0;
                                r = l + width;
                            } else if (r > screenWidth) {
                                r = screenWidth;
                                l = r - width;
                            }
                            if (t < 0) {
                                t = 0;
                                b = t + height;
                            } else if (b > screenHeight) {
                                b = screenHeight;
                                t = b - height;
                            }
    
                            doLayout(l, t, r, b);
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        if (getLeft() + getWidth() / 2 <= screenWidth / 2) {
                            doLayout(0, getTop(), getWidth(), getBottom());
                        } else {
                            doLayout(screenWidth - getWidth(), getTop(), screenWidth, getBottom());
                        }
                        setPressed(false);
                        if (!isDrag) {
                            if (onClickCallback != null) {
                                onClickCallback.onClick(this);
                            }
                        }
                    case MotionEvent.ACTION_CANCEL:
                        setPressed(false);
                        break;
                }
                return true;
            }
            return false;
        }
    
        public OnClickCallback getOnClickCallback() {
            return onClickCallback;
        }
    
        public void setOnClickCallback(OnClickCallback onClickCallback) {
            this.onClickCallback = onClickCallback;
        }
    }
  • After implementing the custom DragView, you also need to put the DragView into a layout with a transparent background. The width and height of this layout must fill the parent layout, and the background needs to be set to a transparent background. Why do you need to do this? The reason is that if our If the DragView is displayed on the game, dragging the DragView will disappear and leave a frame. Adding a parent layout with a transparent background can solve this problem. The following is the layout file
    <?xml version="1.0" encoding="utf-8"?>
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/content_wrap"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent">
    
        <com.lcq.floatview.DragView
            android:id="@+id/floating_menu_div"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_gravity="center_vertical"
            android:scaleType="fitXY"
            android:src="@drawable/qiuqiu"
            android:visibility="visible" />
    </FrameLayout>
  • Then we write a FloatMenu class, load the layout file, and provide show(), dismiss() interfaces and constructors, as follows
    public class FloatMenu {
        private final DragView menuIv;
        private final FrameLayout floatView;
        private final FrameLayout.LayoutParams layoutParams;
        private final Activity activity;
        private boolean addedContentView = false;
    
        public FloatMenu(final Activity activity) {
            this.activity = activity;
            floatView = (FrameLayout) LayoutInflater.from(activity).inflate(R.layout.floating_menu, null);
            menuIv = floatView.findViewById(R.id.floating_menu_div);
            menuIv.setOnClickCallback(new DragView.OnClickCallback() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(activity, "您点击了球球", Toast.LENGTH_LONG).show();
                }
            });
            layoutParams = new FrameLayout.LayoutParams(activity.getResources().getDisplayMetrics().widthPixels,
                    activity.getResources().getDisplayMetrics().heightPixels);
            layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
        }
    
        public void show() {
            if (!addedContentView) {
                activity.getWindow().addContentView(floatView, layoutParams);
                addedContentView = true;
            }
            floatView.setVisibility(View.VISIBLE);
        }
    
        public void dismiss() {
            floatView.setVisibility(View.INVISIBLE);
        }
    }
  • Then build a FloatMenu on the Activity interface that needs to be used, and call the show() and dismiss() interfaces of the FloatMenu in the onResume() and onPause() life cycles of the Activity, for example
    public class MainActivity extends Activity {
        FloatMenu floatMenu;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            floatMenu = new FloatMenu(this);
        }
    
        @Override
        protected void onResume() {
            floatMenu.show();
            super.onResume();
        }
    
        @Override
        protected void onPause() {
            floatMenu.dismiss();
            super.onPause();
        }
    }
  • You can also manually call the show() and dismiss() methods to display or close the floating ball. The interface display effect is as follows
  • If it is a game application, then this method is very practical. You don’t need to apply for permissions, you only need to call related methods in the life cycle of the game’s main interface. If there are many interfaces that need to display floating balls, you can Monitor the life cycle of each Activity in the Activity stack, and create, display, close, and destroy FloatMenu. The specific implementation method will not be described here, you can try it.
  • If you need source code, you can visit this address: https://gitee.com/lin-ciqiao/float-view

 

Guess you like

Origin blog.csdn.net/qq_19942717/article/details/124513846