public class RootView extends RelativeLayout {
private Context mContext;
/**----------可配置属性-------------------*/
/**
* 控制窗口是否能移动
*/
private static boolean canMove = true;
/**
* 是否显示文字
* 注意:在isDisplayFont=true才生效
*/
private static boolean isDisplayFont = true;
/**
* 是否支持长按后才可以移动
*/
private static boolean isCanLongTouchMove = true;
/**
* 悬浮按钮上的文字
* 注意:在isDisplayFont=true才生效
*/
private static String mFont = "标题";
/**
* 文字大小
* 注意:在isDisplayFont=true才生效
*/
private float mFontSize=12;
/**
* 文字的颜色
* 注意:在isDisplayFont=true才生效
*/
private String mFontColor="#000000";
/**
* 文字背景颜色
* 注意:在isDisplayFont=true才生效
*/
private String mFontBgColor="#f24B8DF4";
/**
* 是否显示文本背景颜色
* 注意:在isDisplayFont=true才生效
*/
private boolean isDisplayFontBgColor=true;
/**
* 浮动按钮的背景图片
*/
private int mIconId=R.drawable.floatbar;
/**
* 浮动按钮的大小
*/
private int mWidthAndHeight = 200;
/**
*显示文字的高度,只有在isDisplayFont=true是才生效
*/
private int mDisplayFontHeight = 80;
/**---------------不可配置属性-----------------------*/
private static boolean isMoving = false;
private static boolean isIntercepted = false;
private static boolean isInsideImageView = false;
private static boolean isClickedOnImage = false;
private static boolean onLongTouchCanMove = false;
private int imageId = 001;
private View mMageView = null;
private static final int ON_PLACE_CHANGED=1;
private static final int ON_LONG_TOUCH=100;
private static final int ON_REFRISH_CANVAS=101;
private Timer mTimer;//计时用
private static int mTimesNumber=0;
private Handler mHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int id=msg.what;
switch (id){
case ON_LONG_TOUCH:
onLongTouchCanMove=true;
break;
case ON_PLACE_CHANGED:
break;
case ON_REFRISH_CANVAS:
mMageView.requestLayout();
break;
}
}
};
private int
sX = 0,
sY = 0,
eX = 0,
eY = 0,
mDistanceX = 0,
mDistanceY = 0,
mMarginTop = 0,
mMarginLeft = 0,
mPadding = 5,
mScreenHeight = 0,
mScreenWidth = 0,
mOffset = 200;
public RootView(Context context) {
this(context, null);
}
public RootView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RootView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
init();
}
private void init() {
mHandler.post(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
initView();
}
});
DisplayMetrics mDisplayMetrics = mContext.getResources().getDisplayMetrics();
if (isDisplayFont) {
mScreenWidth = mDisplayMetrics.widthPixels;
mScreenHeight = mDisplayMetrics.heightPixels;
mMarginLeft = mScreenWidth - mWidthAndHeight - mOffset / 2;
mMarginTop = mScreenHeight - mWidthAndHeight - getStatusBarHeight() - mOffset-mDisplayFontHeight;
} else {
mScreenWidth = mDisplayMetrics.widthPixels;
mScreenHeight = mDisplayMetrics.heightPixels;
mMarginLeft = mScreenWidth - mWidthAndHeight - mOffset / 2;
mMarginTop = mScreenHeight - mWidthAndHeight - getStatusBarHeight() - mOffset;
}
}
private void initView() {
MyView mImage = new MyView(mContext);
LayoutParams mFloatLayout = new LayoutParams(mWidthAndHeight, mWidthAndHeight);
mFloatLayout.leftMargin = mMarginLeft;
mFloatLayout.topMargin = mMarginTop;
mFloatLayout.addRule(Gravity.CENTER);
mImage.setLayoutParams(mFloatLayout);
mImage.setId(imageId);
mFloatLayout.addRule(Gravity.CENTER);
mImage.setGravity(Gravity.CENTER);
setViewOnClick(mImage);
ImageView mImageView = new ImageView(mContext);
LayoutParams imageLayout = new LayoutParams(mWidthAndHeight, mWidthAndHeight);
imageLayout.leftMargin = mPadding;
imageLayout.rightMargin = mPadding;
imageLayout.bottomMargin = mPadding+2;
imageLayout.topMargin = mPadding;
imageLayout.addRule(RelativeLayout.CENTER_IN_PARENT);
mImageView.setImageResource(mIconId);
imageLayout.addRule(Gravity.CENTER);
mImageView.setLayoutParams(imageLayout);
mImage.addView(mImageView);
int mChildCount = getChildCount();
if (isDisplayFont) {
LinearLayout outer = new LinearLayout(mContext);
outer.setOrientation(LinearLayout.VERTICAL);
LayoutParams mRoot = new LayoutParams(mWidthAndHeight, mWidthAndHeight+mDisplayFontHeight);
mRoot.leftMargin = mMarginLeft;
mRoot.topMargin = mMarginTop;
outer.setLayoutParams(mRoot);
TextView title = new TextView(mContext);
LayoutParams mTitleLayout = new LayoutParams(LayoutParams.MATCH_PARENT, mDisplayFontHeight);
title.setText(mFont);
if (isDisplayFontBgColor){
title.setBackgroundColor(Color.parseColor(mFontBgColor));
}
title.setTextSize(mFontSize);
title.setTextColor(Color.parseColor(mFontColor));
mTitleLayout.bottomMargin=3;
title.setGravity(Gravity.CENTER);
title.setLayoutParams(mTitleLayout);
outer.addView(mImage);
outer.addView(title);
this.addView(outer, mChildCount);
mMageView = outer;
} else {
this.addView(mImage, mChildCount);
mMageView = mImage;
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mMageView == null) {
int mChildCount = getChildCount();
for (int i = 0; i < mChildCount; i++) {
if (getChildAt(i) instanceof MyView) {
mMageView = getChildAt(i);
}
}
}
if (isInterceptEvent(ev)) {
return true;
} else {
return super.dispatchTouchEvent(ev);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isIntercepted) {
isInterceptEvent(event);
return isIntercepted;
} else {
return super.onTouchEvent(event);
}
}
private void reset(){
mTimesNumber=0;
onLongTouchCanMove=false;
if (mTimer!=null){
try {
mTimer.cancel();
mTimer=null;
} catch (Exception e) {
mTimer=null;
}
}else {
mTimer=null;
}
System.gc();
}
private void calculateTime(){
if (mTimer==null){
mTimer=new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
mTimesNumber++;
if (mTimesNumber==5){
mHandler.sendEmptyMessage(ON_LONG_TOUCH);
try {
mTimer.cancel();
mTimer=null;
} catch (Exception e) {
e.printStackTrace();
} finally {
mTimer=null;
}
}
}
},0,100);
}
}
private boolean isInterceptEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mMageView != null) {
mMageView.setClickable(true);
}
isIntercepted = true;
sX = (int) event.getX();
sY = (int) event.getY();
if (isCanLongTouchMove){
calculateTime();
}
mHandler.sendEmptyMessage(ON_REFRISH_CANVAS);
break;
case MotionEvent.ACTION_MOVE:
isMoving = true;
eX = (int) event.getX();
eY = (int) event.getY();
mDistanceX = eX - sX;
mDistanceY = eY - sY;
sX = eX;
sY = eY;
if (isInsideImageView) {
if (canMove) {
calculate(mDistanceX, mDistanceY);
}
}
break;
case MotionEvent.ACTION_UP:
isInsideImageView = false;
isIntercepted = false;
sX = 0;
sY = 0;
if (isMoving) {
isClickedOnImage = false;
} else {
isClickedOnImage = true;
}
if (mMageView != null) {
mMageView.setClickable(isClickedOnImage);
}
isMoving = false;
if (isCanLongTouchMove){
reset();
}
break;
}
if (!isInsideImageView) {
if (isCanLongTouchMove){
if (onLongTouchCanMove ){
isTouchIn(sX, sY);
}
}else {
isTouchIn(sX, sY);
}
}
if (isInsideImageView && isMoving) {
return true;
} else {
return false;
}
}
private boolean isTouchIn(int sX, int sY) {
if (isDisplayFont){
if ((sX >= mMarginLeft && sX <= (mMarginLeft + mWidthAndHeight)) && (sY >= mMarginTop && sY <= (mMarginTop + mWidthAndHeight))) {
isInsideImageView = true;
return true;
} else {
isInsideImageView = false;
return false;
}
}else {
if ((sX >= mMarginLeft && sX <= (mMarginLeft + mWidthAndHeight)) && (sY >= mMarginTop && sY <= (mMarginTop + mWidthAndHeight))) {
isInsideImageView = true;
return true;
} else {
isInsideImageView = false;
return false;
}
}
}
private void setViewOnClick(MyView viewOnClick) {
viewOnClick.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (isClickedOnImage) {
isClickedOnImage = false;
onFloatingBarClicked();
}
}
});
}
class MyView extends RelativeLayout {
Paint mPaint;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
this.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#00000000")));
mPaint = new Paint();
if (isIntercepted){
mPaint.setColor(Color.parseColor("#7C7784"));
}else {
mPaint.setColor(Color.parseColor("#A8B6AD"));
}
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(mWidthAndHeight/2, mWidthAndHeight/2, mWidthAndHeight/2-3, mPaint);
}
}
private void calculate(int distanceX, int distanceY) {
if (isDisplayFont) {
if ((mMarginTop <= mScreenHeight -mDisplayFontHeight-getStatusBarHeight()) && (mMarginTop >= 1)) {
mMarginTop = mMarginTop + distanceY;
}
if ((mMarginLeft >= 1) && (mMarginLeft <= mScreenWidth - mWidthAndHeight)) {
mMarginLeft = mMarginLeft + distanceX;
}
} else {
if ((mMarginTop <= mScreenHeight - mWidthAndHeight) && (mMarginTop >= 1 )) {
mMarginTop = mMarginTop + distanceY;
}
if ((mMarginLeft >= 1) && (mMarginLeft <= mScreenWidth - mWidthAndHeight)) {
mMarginLeft = mMarginLeft + distanceX;
}
}
startMove();
}
private void startMove() {
if (mMageView != null) {
if (isDisplayFont) {
if (mMarginTop >= mScreenHeight - mWidthAndHeight-mDisplayFontHeight-getStatusBarHeight()) {
mMarginTop = mScreenHeight - mWidthAndHeight-mDisplayFontHeight-getStatusBarHeight()-5 ;
} else if (mMarginTop < 1) {
mMarginTop = 2;
}
}else {
if (mMarginTop >= mScreenHeight - mWidthAndHeight-getStatusBarHeight()) {
mMarginTop = mScreenHeight - mWidthAndHeight-getStatusBarHeight()-5;
} else if (mMarginTop <1) {
mMarginTop = 2;
}
}
if (mMarginLeft <=1) {
mMarginLeft = 2;
} else if (mMarginLeft >= mScreenWidth - mWidthAndHeight) {
mMarginLeft = mScreenWidth - mWidthAndHeight-2;
}
LayoutParams mLayoutParams = (LayoutParams) mMageView.getLayoutParams();
mLayoutParams.leftMargin = mMarginLeft;
mLayoutParams.topMargin = mMarginTop;
mMageView.setLayoutParams(mLayoutParams);
}
}
private int getStatusBarHeight() {
Class<?> c = null;
Object obj = null;
Field field = null;
int x = 0, sbar = 0;
try {
c = Class.forName("com.android.internal.R$dimen");
obj = c.newInstance();
field = c.getField("status_bar_height");
x = Integer.parseInt(field.get(obj).toString());
sbar = getContext().getResources().getDimensionPixelSize(x);
} catch (Exception e1) {
e1.printStackTrace();
}
return sbar;
}
/**
* 点击事件
*/
public void onFloatingBarClicked() {
//TODO .......
Toast.makeText(mContext, "被点击", Toast.LENGTH_SHORT).show();
}
}
布局使用:
<com.example.floatbar.RootView android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent"></ListView> </RelativeLayout>
自定义view组件在布局中使用的时候只能作为容器的父布局,字容器可以用任意多个,且父容器是相对布局
效果图: