当我们在使用的app的时候,如果需要实时观测到某个功能的实时进度并且不影响其他的操作的时候或者不影响使用其他应用的时候,系统级的悬浮球是个非常不错的选择。
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名注册、虚拟空间、营销软件、网站建设、唐县网站维护、网站推广。
public class QueueUpFloatService extends Service {
/**
* 启动服务并传值
*
* @param activity 启动服务的activity
* @param modeBean 数据对象
*/
public static void launchService(Activity activity, ModeBean modeBean) {
try {
Intent intent =new Intent(activity, QueueUpFloatService.class);
Bundle bundle =new Bundle();
bundle.putSerializable(KEY_MODEL, modeBean);
intent.putExtras(bundle);
activity.startService(intent);
}catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
@Override
public void onCreate() {
super.onCreate();
//加一点简单的动画
buttonScale = (ScaleAnimation) AnimationUtils.loadAnimation(this, R.anim.anim_float);
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
layoutParams =new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT = Build.VERSION_CODES.O) {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else {
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
layoutParams.format = PixelFormat.RGBA_8888;
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
layoutParams.width = ScreenUtils.dp2px(66);
layoutParams.height = ScreenUtils.dp2px(66);
layoutParams.x = ScreenUtils.getRealWidth() - ScreenUtils.dp2px(60);
layoutParams.y = ScreenUtils.deviceHeight() *2 /3;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
ModeBean modeBean = (ModeBean) intent.getExtras().getSerializable(KEY_MODEL);
LayoutInflater layoutInflater = LayoutInflater.from(this);
floatView = layoutInflater.inflate(R.layout.view_float, null);
RelativeLayout rlFloatParent =floatView.findViewById(R.id.rl_float_parent);
rlFloatParent.startAnimation(buttonScale);
TextView tvIndex =floatView.findViewById(R.id.tv_queue_index);
tvIndex.setText(modeBean.title);
floatView.findViewById(R.id.iv_close_float).setOnClickListener(v - stopSelf());
//修改悬浮球的滑动实现
floatView.setOnTouchListener(new FloatingOnTouchListener());
windowManager.addView(floatView, layoutParams);
return super.onStartCommand(intent, flags, startId);
}
private class FloatingOnTouchListenerimplements View.OnTouchListener {
private int x;
private int y;
private long downTime;
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downTime = System.currentTimeMillis();
x = (int) event.getRawX();
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int nowX = (int) event.getRawX();
int nowY = (int) event.getRawY();
int movedX = nowX -x;
int movedY = nowY -y;
x = nowX;
y = nowY;
layoutParams.x =layoutParams.x + movedX;
layoutParams.y =layoutParams.y + movedY;
windowManager.updateViewLayout(view, layoutParams);
break;
case MotionEvent.ACTION_UP:
/* *
* 这里根据手指按下和抬起的时间差来判断点击事件还是滑动事件
* */
if ((System.currentTimeMillis() -downTime) 200) {
//检测应用在前台还是后台
if (AppUtils.isAppIsInBackground()) {
AppUtils.moveToFront(CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1).getClass());
} else {
//检测栈顶是否为SecondActivity 不是就打开SecondActivity
if (!CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1)
.getClass().getSimpleName().contains("SecondActivity")) {
SecondActivity.launchActivity(CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1));
}
}
}
break;
default:
break;
}
return false;
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (null ==floatView) {
return;
}
windowManager.removeView(floatView);
windowManager=null;
}
如果您想关闭悬浮导航,进入设置 系统和更新 系统导航方式 更多 或设置 系统和更新 系统导航方式 悬浮导航 (取决于您的机型),关闭悬浮导航开关。
android悬浮按钮(Floating action button)的两种实现方法
最近android中有很多新的设计规范被引入,最流行的莫过于被称作Promoted Actions的设计了,Promoted Actions是指一种操作按钮,它不是放在actionbar中,而是直接在可见的UI布局中(当然这里的UI指的是setContentView所管辖的范围)。因此它更容易在代码中被获取到(试想如果你要在actionbar中获取一个菜单按钮是不是很难?),Promoted Actions往往主要用于一个界面的主要操作,比如在email的邮件列表界面,promoted action可以用于接受一个新邮件。promoted action在外观上其实就是一个悬浮按钮,更常见的是漂浮在界面上的圆形按钮,一般我直接将promoted action称作悬浮按钮,英文名称Float Action Button 简称(FAB,不是FBI哈)。
float action button是android l中的产物,但是我们也可以在更早的版本中实现。假设我这里有一个列表界面,我想使用floataction button代表添加新元素的功能,界面如下:
要实现float action button可以有多种方法,一种只适合android L,另外一种适合任意版本。
用ImageButton实现
这种方式其实是在ImageButton的属性中使用了android L才有的一些特性:
ImageButton
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/plus"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:tint="@android:color/white"
android:id="@+id/fab"
android:elevation="1dp"
android:background="@drawable/ripple"
android:stateListAnimator="@anim/fab_anim"
/
仔细一点,你会发现我们将这个ImageButton放到了布局的右下角,为了实现float action button应该具备的效果,需要考虑以下几个方面:
·Background
·Shadow
·Animation
背景上我们使用ripple drawable来增强吸引力。注意上面的xml代码中我们将background设置成了@drawable/ripple ,ripple drawable的定义如下:
ripple xmlns:android="" android:color="?android:colorControlHighlight"
item
shape android:shape="oval"
solid android:color="?android:colorAccent" /
/shape
/item
/ripple
既然是悬浮按钮,那就需要强调维度上面的感觉,当按钮被按下的时候,按钮的阴影需要扩大,并且这个过程是渐变的,我们使用属性动画去改变translatioz。
selector xmlns:android=""
item
android:state_enabled="true"
android:state_pressed="true"
objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="translationZ"
android:valueFrom="@dimen/start_z"
android:valueTo="@dimen/end_z"
android:valueType="floatType" /
/item
item
objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="translationZ"
android:valueFrom="@dimen/end_z"
android:valueTo="@dimen/start_z"
android:valueType="floatType" /
/item
/selector
使用自定义控件的方式实现悬浮按钮
这种方式不依赖于android L,而是码代码。
首先定义一个这样的类:
public class CustomFAB extends ImageButton {
...
}
然后是读取一些自定义的属性(假设你了解styleable的用法)
private void init(AttributeSet attrSet) {
Resources.Theme theme = ctx.getTheme();
TypedArray arr = theme.obtainStyledAttributes(attrSet, R.styleable.FAB, 0, 0);
try {
setBgColor(arr.getColor(R.styleable.FAB_bg_color, Color.BLUE));
setBgColorPressed(arr.getColor(R.styleable.FAB_bg_color_pressed, Color.GRAY));
StateListDrawable sld = new StateListDrawable();
sld.addState(new int[] {android.R.attr.state_pressed}, createButton(bgColorPressed));
sld.addState(new int[] {}, createButton(bgColor));
setBackground(sld);
}
catch(Throwable t) {}
finally {
arr.recycle();
}
}
在xml中我们需要加入如下代码,一般是在attr.xml文件中。
?xml version="1.0" encoding="utf-8"?
resources
declare-styleable name="FAB"
!-- Background color --
attr name="bg_color" format="color|reference"/
attr name="bg_color_pressed" format="color|reference"/
/declare-styleable
/resources
使用StateListDrawable来实现不同状态下的背景
private Drawable createButton(int color) {
OvalShape oShape = new OvalShape();
ShapeDrawable sd = new ShapeDrawable(oShape);
setWillNotDraw(false);
sd.getPaint().setColor(color);
OvalShape oShape1 = new OvalShape();
ShapeDrawable sd1 = new ShapeDrawable(oShape);
sd1.setShaderFactory(new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
LinearGradient lg = new LinearGradient(0,0,0, height,
new int[] {
Color.WHITE,
Color.GRAY,
Color.DKGRAY,
Color.BLACK
}, null, Shader.TileMode.REPEAT);
return lg;
}
});
LayerDrawable ld = new LayerDrawable(new Drawable[] { sd1, sd });
ld.setLayerInset(0, 5, 5, 0, 0);
ld.setLayerInset(1, 0, 0, 5, 5);
return ld;
}
最后将控件放xml中:
RelativeLayout xmlns:android=""
xmlns:tools=""
xmlns:custom=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MyActivity"
...
com.survivingwithandroid.fab.CustomFAB
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@android:drawable/ic_input_add"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
custom:bg_color="@color/light_blue"
android:tint="@android:color/white"
/
/RelativeLayout