package com.bg7yoz.ft8cn.floatview; /** * FloatButton的主界面 * @author BGY70Z * @date 2023-03-20 */ import android.annotation.SuppressLint; import android.content.Context; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.ImageButton; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import androidx.constraintlayout.widget.Constraints; import java.util.ArrayList; public class FloatView extends ConstraintLayout { private static final String TAG = "FloatView"; public enum FLOAT_BOARD { LEFT, RIGHT, TOP, BUTTON } private int parentViewHeight = 100;//上一级view的高度 private int parentViewWidth = 100;//上一级view的宽度 private float mDownX = 0; private float mDownY = 0; private int lastLeft = 0; private int lastTop = 0; //------------悬浮窗口的属性-------------------- private int buttonSize = 96;//按钮的大小 private final ArrayList buttons = new ArrayList<>(); private boolean originalFromTop = false;//是否上下靠边 private boolean originalFromLeft = true;//是否左右靠边 private int buttonBackgroundResourceId = -1;//按钮的背景 private int backgroundResourceId = -1;//浮窗的背景 private int buttonMargin = 0;//按钮在浮窗中的边界宽度 private int floatMargin = 40;//浮窗距离边界的距离 private FLOAT_BOARD floatBoard = FLOAT_BOARD.LEFT; /** * 构造函数,需要大小 * * @param context context * @param buttonSize 按钮大小,正方形 */ public FloatView(@NonNull Context context, int buttonSize) { this(context); this.buttonSize = buttonSize; } public FloatView(@NonNull Context context) { this(context, null); } public FloatView(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public FloatView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } public FloatViewButton addButton(String name, int imageResourceId, OnClickListener onClickListener) { FloatViewButton floatViewButton=getButtonByName(name); if (floatViewButton==null){ floatViewButton =addButton(View.generateViewId(), imageResourceId, onClickListener); } floatViewButton.setName(name); return floatViewButton; } public FloatViewButton addButton(int id, String name, int imageResourceId, OnClickListener onClickListener) { FloatViewButton floatViewButton=getButtonByName(name); if (floatViewButton==null){ floatViewButton = addButton(id, imageResourceId, onClickListener); } floatViewButton.setName(name); return floatViewButton; } public FloatViewButton addButton(int id, int imageResourceId, OnClickListener onClickListener) { FloatViewButton imageButton = new FloatViewButton(getContext()); //imageButton.setScaleType(ImageView.ScaleType.FIT_CENTER); imageButton.setImageResource(imageResourceId); if (buttonBackgroundResourceId != -1) { imageButton.setBackgroundResource(buttonBackgroundResourceId); } //imageButton.setId(R.id.float_nav); imageButton.setId(id); imageButton.setOnClickListener(onClickListener); imageButton.setAlpha(0.5f); addView(imageButton); buttons.add(imageButton); resetView(); return imageButton; } /** * 通过按钮的名称删除按钮 * * @param name 按钮的名称 */ public void deleteButtonByName(String name) { for (int i = buttons.size() - 1; i >= 0; i--) { FloatViewButton floatViewButton = buttons.get(i); if (floatViewButton.getName().equals(name)) { buttons.remove(i); removeView(floatViewButton); } resetView(); } } public void deleteButtonByIndex(int index) { if (buttons.size() > index && index > -1) { FloatViewButton floatViewButton = buttons.get(index); buttons.remove(index); removeView(floatViewButton); resetView(); } } public FloatViewButton getButtonByName(String name) { for (FloatViewButton button : buttons) { if (button.getName().equals(name)) { return button; } } return null; } /** * 把dp值转换为像素点 * * @param dp dp值 * @return 像素点 */ private int dpToPixel(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp , getResources().getDisplayMetrics()); // return (int) (dp*getResources().getDisplayMetrics().density); } /** * 重新设置一下按钮 */ public void resetView() { for (int i = 0; i < buttons.size(); i++) { //LayoutParams buttonLp = new LayoutParams(buttonSize, buttonSize); LayoutParams buttonLp = new LayoutParams(dpToPixel(buttonSize), dpToPixel(buttonSize)); buttonLp.startToStart = ConstraintSet.PARENT_ID; buttonLp.endToEnd = ConstraintSet.PARENT_ID; buttonLp.leftMargin = buttonMargin; buttonLp.rightMargin = buttonMargin; if (i == 0) { buttonLp.topToTop = ConstraintSet.PARENT_ID; buttonLp.topMargin = buttonMargin; } else { buttonLp.topToBottom = buttons.get(i - 1).getId(); buttonLp.topMargin = buttonMargin+dpToPixel(4);//按钮之间留一点点空隙 } if (i == buttons.size() - 1) { buttonLp.bottomToBottom = ConstraintSet.PARENT_ID; buttonLp.bottomMargin = buttonMargin; } buttons.get(i).setLayoutParams(buttonLp); } } @SuppressLint("ClickableViewAccessibility") private void initView() { LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);// LayoutParams.WRAP_CONTENT); lp.startToStart = ConstraintSet.PARENT_ID;//只连接窗口的左边和上边 lp.topToTop = ConstraintSet.PARENT_ID; this.setLayoutParams(lp); } public void initLocation() { initLocation(this.floatBoard); } /** * 初始化浮窗的位置,默认在窗口的右侧, */ public void initLocation(FLOAT_BOARD float_board) { this.floatBoard = float_board; getParentViewHeightAndWidth(); int width; int height; if (parentViewWidth == 0 && parentViewHeight == 0) { WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); width = wm.getDefaultDisplay().getWidth(); height = wm.getDefaultDisplay().getHeight(); } else {//这部分基本没有执行过 width = parentViewWidth; height = parentViewHeight; } switch (float_board) { case RIGHT: setLayoutLeftTop(width - dpToPixel(floatMargin * 2 - buttonSize) - 10 , (int) (height / 2f - dpToPixel(buttonMargin + buttonSize * buttons.size())/2f)); break; case LEFT: setLayoutLeftTop(floatMargin + 10 , (int) (height / 2f - dpToPixel(buttonMargin + buttonSize * buttons.size() )/2f)); break; case TOP: setLayoutLeftTop((int) (width / 2f - dpToPixel(buttonMargin - buttonSize) / 2f), floatMargin); break; case BUTTON: setLayoutLeftTop((int) (width / 2f - dpToPixel(buttonMargin - buttonSize) / 2f) , height - dpToPixel(floatMargin - buttonMargin * 2 - buttonSize * buttons.size())); break; } } /** * 获取父View的高度和宽度 */ private void getParentViewHeightAndWidth() { View view = (View) getParent(); if (view != null) { parentViewHeight = view.getHeight(); parentViewWidth = view.getWidth(); } } public void setLayoutLeftTop(int left, int top) { ConstraintLayout.LayoutParams layoutParams = new Constraints.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT , ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.topToTop = ConstraintSet.PARENT_ID; layoutParams.startToStart = ConstraintSet.PARENT_ID; layoutParams.leftMargin = left; layoutParams.topMargin = top; setLayoutParams(layoutParams); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mDownX = event.getX(); mDownY = event.getY(); break; case MotionEvent.ACTION_MOVE: offsetTopAndBottom((int) (event.getY() - mDownY)); offsetLeftAndRight((int) (event.getX() - mDownX)); lastLeft = getLeft(); lastTop = getTop(); setLayoutLeftTop(getLeft(), getTop()); case MotionEvent.ACTION_UP: setLayoutLeftTop(lastLeft, lastTop); adsorbTopAdnBottom();//吸附上下 adsorbLeftAndRight();//吸附左右 break; case MotionEvent.ACTION_CANCEL: break; } return super.onInterceptTouchEvent(event); } private void adsorbTopAdnBottom() { if (originalFromTop) { getParentViewHeightAndWidth(); float boundaryLine = parentViewHeight / 4f; if (getTop() < boundaryLine) { setLayoutLeftTop(getLeft(), floatMargin); } else if (getBottom() > parentViewHeight - boundaryLine) { setLayoutLeftTop(getLeft(), parentViewHeight - getHeight() - floatMargin); } } } private void adsorbLeftAndRight() { if (originalFromLeft) { getParentViewHeightAndWidth(); float boundaryLine = parentViewWidth / 4f; if (getLeft() < boundaryLine) { setLayoutLeftTop(floatMargin, getTop()); } else if (getRight() > parentViewWidth - boundaryLine) { setLayoutLeftTop(parentViewWidth - getWidth() - floatMargin, getTop()); //animate().setInterpolator(new DecelerateInterpolator()).setDuration(300).x(parentViewWidth - getWidth() - floatMargin).start(); } } } public boolean isOriginalFromTop() { return originalFromTop; } public void setOriginalFromTop(boolean originalFromTop) { this.originalFromTop = originalFromTop; } public boolean isOriginalFromLeft() { return originalFromLeft; } public void setOriginalFromLeft(boolean originalFromLeft) { this.originalFromLeft = originalFromLeft; } public int getButtonBackgroundResourceId() { return buttonBackgroundResourceId; } public void setButtonBackgroundResourceId(int buttonBackgroundResourceId) { this.buttonBackgroundResourceId = buttonBackgroundResourceId; for (ImageButton button : this.buttons) { button.setBackgroundResource(buttonBackgroundResourceId); } } public int getBackgroundResourceId() { return backgroundResourceId; } public void setBackgroundResourceId(int backgroundResourceId) { this.setBackgroundResource(backgroundResourceId); this.backgroundResourceId = backgroundResourceId; } public int getButtonMargin() { return buttonMargin; } public void setButtonMargin(int buttonMargin) { this.buttonMargin = buttonMargin; } public int getFloatMargin() { return floatMargin; } public void setFloatMargin(int floatMargin) { this.floatMargin = floatMargin; } public FLOAT_BOARD getFloatBoard() { return floatBoard; } public void setFloatBoard(FLOAT_BOARD float_board) { this.floatBoard = float_board; } }