- 一般在接入渠道SDK的时候,他们的SDK里面都会带有悬浮球,并且浮动显示在您的应用之上的,当点击悬浮球就能弹出菜单栏或者游戏中心、用户中心之类的页面,有些SDK的实现是需要申请权限的,如果用户不给权限,那么悬浮球功能将无法使用了,这种方式肯定是不行的,下面我们就来实现一种依附在Activity页面上的悬浮球。
- 首先我们需要自定义一个View,可以继承ImageView、或者其他View,然后重新onMeasure、onDraw、onTouchEvent等方法来实现拖动的逻辑
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; } }
- 实现好了自定义DragView后,还需要将DragView放入一个透明背景的布局,这个布局的宽和高都要充满父布局,背景需要设置为透明背景,为什么需要这样做呢,原因是如果我们的DragView显示在游戏上面的话,进行拖拽DragView会消失,并且留下一个框框,加个透明背景的父布局就能解决这个问题了,如下是布局文件
<?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>
- 然后我们再写一个FloatMenu类,将这个布局文件进行加载,并提供show()、dismiss()接口以及构造函数,如下
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); } }
- 然后在需要使用的Activity界面,构建一个FloatMenu,在Activity的onResume()、onPause() 生命周期里分别调用FloatMenu的show()、dismiss()接口,比如
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(); } }
- 你也可以手动进行调用show()和dismiss()方法展示或关闭悬浮球,界面显示效果如下
- 如果是游戏应用的话,那么这种方式就很实用了,不需要申请权限、只需要在游戏主界面的生命周期里面调用相关的方法就可以了,如果是有很多界面需要展示悬浮球的话,可以对Activity栈里的每个Activity的生命周期进行监听,并创建、显示、关闭、销毁FloatMenu。具体的实现方式这里就不讲述了,大家可以去试试。
- 如果需要源码的可以访问这个地址:https://gitee.com/lin-ciqiao/float-view
Android 基于Activity的悬浮球实现,无需申请悬浮框权限、适合展示在游戏主页之上
猜你喜欢
转载自blog.csdn.net/qq_19942717/article/details/124513846
今日推荐
周排行