转载请注明优快云博文地址:http://blog.youkuaiyun.com/ls0609/article/details/77162417
在线听书demo:http://blog.youkuaiyun.com/ls0609/article/details/71519203
语音记账demo:http://blog.youkuaiyun.com/ls0609/article/details/72765789
android桌面悬浮窗实现比较简单,本篇以一个语音识别,语义理解的demo来演示如何实现android悬浮窗。
1.悬浮窗效果
桌面上待机的时候,悬浮窗吸附在边上
拖动远离屏幕边缘时图标变大,松开自动跑到屏幕边缘,距离屏幕左右边缘靠近哪边吸附哪边
点击悬浮图标时,启动录音
说完后可以点击左button,上传录音给服务器等待处理返回结果
服务器返回结果后自动跳转到应用界面,本例用的是在线听书,跳转到在线听书的界面
2.FloatViewIdle与FloatViewIdleService
1.FloatViewIdle
定义一个FloatViewIdle类,如下是该类的单例模式
public static synchronized FloatViewIdle getInstance(Context context)
{
if(floatViewManager == null)
{
mContext = context.getApplicationContext();;
winManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
displayWidth = winManager.getDefaultDisplay().getWidth();
displayHeight = winManager.getDefaultDisplay().getHeight();
floatViewManager = new FloatViewIdle();
}
return floatViewManager;
}
利用winManager 的addview方法,把自定义的floatview添加到屏幕中,那么就会在任何界面显示该floatview,然后再屏蔽非待机界面隐藏floatview,这样就只有待机显示悬浮窗了。
定义两个自定义view,分别是FloatIconView和FloatRecordView,前者就是待机看到的小icon图标,后者是点击这个icon图标后展示的录音的那个界面。
下面来看下怎么定义的FloatIconView
class FloatIconView extends LinearLayout{
private int mWidth;
private int mHeight;
private int preX;
private int preY;
private int x;
private int y;
public boolean isMove;
public boolean isMoveToEdge;
private FloatViewIdle manager;
public ImageView imgv_icon_left;
public ImageView imgv_icon_center;
public ImageView imgv_icon_right;
public int mWidthSide;
public FloatIconView(Context context) {
super(context);
View view = LayoutInflater.from(mContext).
inflate(R.layout.layout_floatview_icon, this);
LinearLayout layout_content =
(LinearLayout) view.findViewById(R.id.layout_content);
imgv_icon_left = (ImageView) view.findViewById(R.id.imgv_icon_left);
imgv_icon_center = (ImageView) view.findViewById(R.id.imgv_icon_center);
imgv_icon_right = (ImageView) view.findViewById(R.id.imgv_icon_right);
imgv_icon_left.setVisibility(View.GONE);
imgv_icon_center.setVisibility(View.GONE);
mWidth = layout_content.getWidth();
mHeight = layout_content.getHeight();
if((mWidth == 0)||(mHeight == 0))
{
int temp = DensityUtil.dip2px(mContext, icon_width);
mHeight = temp;
icon_width_side_temp = DensityUtil.dip2px(mContext, icon_width_side);
mWidth = icon_width_side_temp;
}
manager = FloatViewIdle.getInstance(mContext);
if(params != null)
{
params.x = displayWidth - icon_width_side_temp;
params.y = displayHeight/2;
}
}
public int getFloatViewWidth()
{
return mWidth;
}
public int getFloatViewHeight()
{
return mHeight;
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
preX = (int)event.getRawX();
preY = (int)event.getRawY();
isMove = false;
if(params.width == icon_width_side_temp)
handler.sendMessage(handler.obtainMessage(
MSG_UPDATE_FLOAT_VIEW_AFTER_CHANGED, 3, 0));
break;
case MotionEvent.ACTION_UP:
if(isMoveToEdge == true)
{
if(params.width == icon_width_side_temp)
handler.sendMessage(handler.obtainMessage(
MSG_UPDATE_FLOAT_VIEW_AFTER_CHANGED, 3, 0));
handler.sendMessage(handler.obtainMessage(
MSG_FLOAT_VIEW_MOVE_TO_EDGE,this));
}
break;
case MotionEvent.ACTION_MOVE:
x = (int)event.getRawX();
y = (int)event.getRawY();
if(Math.abs(x-preX)>1||Math.abs(y-preY)>1)
{
isMoveToEdge = true;
}
if(Math.abs(x-preX)>5||Math.abs(y-preY)>5)
isMove = true;
if(params.width == icon_width_side_temp)
handler.sendMessage(handler.obtainMessage(
MSG_UPDATE_FLOAT_VIEW_AFTER_CHANGED, 3, 0));
manager.move(this, x-preX, y-preY);
preX = x;
preY = y;
break;
}
return super.onTouchEvent(event);
}
}
通过layout文件生成一个FloatIconView,在onTouchEvent函数中当按下的时候,发送消息更新悬浮view,抬起即up事件时先更新悬浮view,然后再显示吸附到边上的动画。 当move的时候,判断每次位移至少5和像素则更新view位置,这样不断move不断更新就会形成连续的画面。
另一个FloatRecordView(录音的悬浮窗)道理相同,这