现在很多软件都有悬浮框功能,比如Facebook,体验效果极佳。
先下载体验下悬浮窗吧,apk地址: http://download.csdn.net/detail/zz7zz7zz/6454107
其他不说,直接步入正题看看具体的实现吧。
一、效果图:
二、实现知识点:
1. WindowManager
addView(View view, LayoutParams params) ,添加一个悬浮窗
updateViewLayout(View view, LayoutParams params),要使悬浮窗做出改变,需通过改变params的属性,并调用此方法更新。
removeView()移除一个悬浮窗。
2. WindowManager.LayoutParams属性的设置。
WindowManager.LayoutParams mParams=new WindowManager.LayoutParams();
mParams.type=WindowManager.LayoutParams.TYPE_PHONE;//悬浮窗的类型
mParams.format= PixelFormat.RGBA_8888; //效果为透明
mParams.flags=
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; //悬浮窗的行为,比如说不可聚焦,不可触摸,全屏对等
mParams.width=100;//指定悬浮窗的宽度
mParams.height=100;//指定悬浮窗的高度。
mParams.gravity=Gravity.LEFT|Gravity.TOP; //悬浮窗的对齐方式
mParams.x=0; //悬浮窗的横坐标
mParams.y=0;//悬浮窗的纵坐标
3. 其他一些动画效果,通过重写View或者使用 SurfaceView作为补间动画。
public interface IAnimation
{
public abstract void onAnimStart();
public abstract void onAnimDraw(SurfaceHolder holder);
public abstract void onAnimEnd();
}
4. 用Service 来控制动画
三、具体代码
1. AndroidManifest.xml中的配置
权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
其他配置:
<!-- 悬浮框 开始 -->
<meta-data android:name="tooltipdata" android:value="com.open.MainActivity" />
<service android:name="com.open.tooltip.TooltipService" android:exported="false">
</service>
<!-- 悬浮框 接收 -->
2.ChatBall,悬浮的小球
package com.open.tooltip;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
/**
* 小球
* @author DexYang
*
*/
public class ChatBall extends ImageView{
private final String TAG="ChatBall";
public ChatBall(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public ChatBall(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ChatBall(Context context) {
super(context);
init(context);
}
private void init(Context context)
{
this.setImageResource(R.drawable.tooltip_icon_f);
this.setOnTouchListener(onTouchListener);
}
private OnTouchListener onTouchListener=new OnTouchListener() {
private boolean isMove=false;
private Rect mViewRect=new Rect();
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
isMove=false;
//有些机子上调用下面代码无效
// int[] location = new int[2];
// v.getLocationOnScreen(location);
// mViewRect.set(location[0], location[1], location[0]+TooltipMgr.getInstance().getBallWidth(), location[1]+TooltipMgr.getInstance().getBallHeight());
int left=TooltipMgr.getInstance().src[0]-TooltipMgr.getInstance().getBallWidth()/2;
int top=TooltipMgr.getInstance().src[1]-TooltipMgr.getInstance().getBallHeight()/2;
mViewRect.set(left, top, left+TooltipMgr.getInstance().getBallWidth(), top+TooltipMgr.getInstance().getBallHeight());
break;
case MotionEvent.ACTION_MOVE:
if(!isMove)
{
int _lastX = (int) event.getRawX();
int _lastY = (int) event.getRawY()-TooltipMgr.getInstance().getStatusBarHeight(getContext());
if(!mViewRect.contains(_lastX, _lastY))
{
isMove=true;
if(ToolTipConfig.isUseSurfaceView)
{
Bundle mBundle=new Bundle();
mBundle.putIntArray("data", new int[]{_lastX,_lastY});
TooltipMgr.getInstance().updateUI(getContext(), TooltipMgr.STATUS_BALL_DRAG, mBundle);
}
TooltipMgr.getInstance().updataChatBall(event);
}
}
else
{
TooltipMgr.getInstance().updataChatBall(event);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if(isMove)
{
TooltipMgr.getInstance().updataChatBall(event);
}
else
{
TooltipMgr.getInstance().updateUI(getContext(), TooltipMgr.STATUS_CHATWINDOW_OPEN, null);
}
break;
}
return true;
}
};
}
3. TooltipService