现在很多软件都有悬浮框功能,比如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 控制悬浮框在哪些界面显示,哪些界面不显示(通过循环查询的方式)
package com.open.tooltip; import java.util.ArrayList; import java.util.List; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Handler; import android.os.IBinder; import android.text.TextUtils; import android.util.Log; /** * 控制悬浮框 * @author DexYang * */ public class TooltipService extends Service { private final String TAG="TooltipService"; private ArrayList<String> mActivityList=new ArrayList<String>(); private Handler mHandler=new Handler(); @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onCreate() { Log.v(TAG, "onCreate"); super.onCreate(); TooltipMgr.getInstance().init(getApplicationContext()); mHandler.post(heartRunnable); try { ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(),PackageManager.GET_META_DATA); if(null!=appInfo.metaData) { String mActivityNames=appInfo.metaData.getString("tooltipdata"); if(!TextUtils.isEmpty(mActivityNames)) { String[] names=mActivityNames.split("\\|"); for(int i=0;i<names.length;i++) { if(!TextUtils.isEmpty(names[i])&&!mActivityList.contains(names[i])) { mActivityList.add(names[i]); Log.v(TAG, " onCreate Activity:"+names[i]); } } } } } catch (Exception e) { e.printStackTrace(); } } @Override public void onDestroy() { Log.v(TAG, "onDestroy"); mHandler.removeCallbacks(heartRunnable); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if(null!=intent) { int command=intent.getIntExtra("command", TooltipMgr.STATUS_OPEN); if(command==TooltipMgr.STATUS_MESSAGE_ADD) { int size=TooltipMgr.getInstance().getMessageList().size(); if(size==0) { command=TooltipMgr.STATUS_MESSAGE_NULL2FULL; } else { command=TooltipMgr.STATUS_MESSAGE_ADD; } TooltipMgr.getInstance().updateData(intent.getExtras()); if(isContain()) { TooltipMgr.getInstance().updateUI(getApplicationContext(),command,intent.getExtras()); } } else if(command==TooltipMgr.REGISTER_TOOLTIP) { String mActivity=intent.getExtras().getString("data"); if(!TextUtils.isEmpty(mActivity)&&!mActivityList.contains(mActivity)) { mActivityList.add(mActivity); } } else if(command==TooltipMgr.STATUS_CLOSE) { TooltipMgr.getInstance().closeWindows(); mHandler.post(heartRunnable); this.stopSelf(); } } return super.onStartCommand(intent, flags, startId); } /** * 检测当前界面是不是要显示的界面 */ private Runnable heartRunnable=new Runnable() { @Override public void run() { // Log.v(TAG, "heartRunnable"); if(isContain()) { if(TooltipMgr.getInstance().isChatBallAddWindow||TooltipMgr.getInstance().isChatUIAddWindow||TooltipMgr.getInstance().isAnimViewAddWindow) { } else { TooltipMgr.getInstance().onResume(); } } else { TooltipMgr.getInstance().onPause(); } mHandler.postDelayed(this, 1000L); } }; private boolean isContain() { ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<RunningTaskInfo> mRunningTaskInfo = mActivityManager.getRunningTasks(1); String topActivityName=mRunningTaskInfo.get(0).topActivity.getClassName(); boolean isContain=false; for(int i=0;i<mActivityList.size();i++) { isContain=mActivityList.contains(topActivityName); if(isContain) { break; } } return isContain; } @Override public void onConfigurationChanged(Configuration newConfig) { Log.v(TAG, "onConfigurationChanged()"); if(TooltipMgr.getInstance().getScreenWidth()!=TooltipMgr.getInstance().getWindowManager().getDefaultDisplay().getWidth()) { TooltipMgr.getInstance().onConfigurationChanged(); } super.onConfigurationChanged(newConfig); } }
package com.open.tooltip; import java.lang.ref.SoftReference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import com.open.data.ChatMsg; import com.open.tooltip.anim.BallDragAnim; import com.open.tooltip.anim.BallDragAnimTail; import com.open.tooltip.anim.IAnimation; import com.open.tooltip.anim.MessageDragAnim; import com.open.tooltip.anim.TransAnim; import com.open.tooltip.anim.TransAnimShadow; /** * 管理布局 * @author DexYang * */ public class TooltipMgr { private final String TAG="TooltipMgr"; public static final int STATUS_OPEN=1;//开始悬浮框 public static final int STATUS_CLOSE=2;//关闭所有悬浮窗 public static final int STATUS_MESSAGE_NULL2FULL=3;//无消息→有消息 public static final int STATUS_MESSAGE_ADD=4;//有消息→添加了新消息 public static final int STATUS_MESSAGE_FULL2NULL=5;//有消息→无消息 public static final int STATUS_CHATWINDOW_OPEN=6;//点击小球,动画开始 public static final int STATUS_CHATWINDOW_EXPAND=7;//有消息,展开聊天窗口 public static final int STATUS_CHATWINDOW_DRAWBACK=8;//点击对话框,收缩 public static final int STATUS_CHATWINDOW_CLOSE=9;//有消息,收缩 public static final int STATUS_CHATWINDOW_DRAWBACK_MESSAGE_NULL=10;//点击对话框,收缩 public static final int STATUS_BALL_DRAG=11;//拖拽小球 public static final int STATUS_BALL_DRAG_END=12;//拖拽小球,松手 public static final int STATUS_BALL_DRAG_END_BALL=13;//松手后,从新显示小球 public static final int STATUS_RECRODING_START=14;//录音 public static final int STATUS_RECRODING_STOP=15;//录音 public static final int STATUS_MESSAGE_DRAG=16;//拖拽消息头像 public static final int STATUS_MESSAGE_DRAG_DELETE_SUCCESS=17;//拖拽消息头像结束,并且删除成功 public static final int STATUS_MESSAGE_DRAG_DELETE_FAILED=18;//拖拽消息头像结束,并且删除失败 public static final int STATUS_MESSAGE_DRAG_FLASHVIEW_END=19;//拖拽消息头像结束 public static final int REGISTER_TOOLTIP=100;//注册悬浮框,注册过才可以显示 private WindowManager mWindowManager; private ChatBall mChatBall;//小球 private ChatUI mChatUI;//聊天框 private AnimSurfaceView mAnimSurfaceView;//小球动画 private AudioRecordMicView mMicImageView;//麦克风 private WindowManager.LayoutParams mChatBallParams; private WindowManager.LayoutParams mChatUIParams; private WindowManager.LayoutParams mAnimSurfaceViewParams; private WindowManager.LayoutParams mMicParams; public boolean isChatBallAddWindow=false;//小球是否添加了 public boolean isChatUIAddWindow=false;//对话框是否添加了 public boolean isAnimViewAddWindow=false;//动画View是否添加了 private int statusBarHeight;//系统状态栏的高度 private int screenWidth; private int screenHeight; private int mBallWidth; private int mBallHeight; public int []src=new int[]{0,0};//初始点 private final int []des=new int[]{0,0};//左上角 private BallDragAnim mBallDragAnim=null; private MessageDragAnim mMessageDragAnim=null; private ArrayList<DrawMessage> msgArrayList=new ArrayList<DrawMessage>(5); private Context mContext; private Handler mHandler; private static TooltipMgr instance; private TooltipMgr(){} public static TooltipMgr getInstance() { if(null==instance) { instance=new TooltipMgr(); } return instance; } public void init(Context context) { if(null==mContext) { mContext=context.getApplicationContext(); mWindowManager=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mHandler=new Handler(context.getMainLooper()); Drawable ballIcon=context.getResources().getDrawable(R.drawable.tooltip_icon_nf); mBallWidth=ballIcon.getIntrinsicWidth(); mBallHeight=ballIcon.getIntrinsicHeight(); des[0]=mBallWidth/2; des[1]=mBallHeight/2; src[0]=getScreenWidth()-mBallWidth/2; src[1]=(getScreenHeight()-getStatusBarHeight(context))/2; getChatBallParam(context); getChatUIParam(context); } } public WindowManager getWindowManager() { return mWindowManager; } public int getStatusBarHeight(Context context) { if (statusBarHeight == 0) { try { Class<?> c = Class.forName("com.android.internal.R$dimen"); Object o = c.newInstance(); Field field = c.getField("status_bar_height"); int x = (Integer) field.get(o); statusBarHeight = context.getResources().getDimensionPixelSize(x); } catch (Exception e) { e.printStackTrace(); } } return statusBarHeight; } public int getScreenWidth() { if(screenWidth==0) { screenWidth =mWindowManager.getDefaultDisplay().getWidth(); screenHeight=mWindowManager.getDefaultDisplay().getHeight(); } return screenWidth; } public int getScreenHeight() { if(screenHeight==0) { screenWidth =mWindowManager.getDefaultDisplay().getWidth(); screenHeight=mWindowManager.getDefaultDisplay().getHeight(); } return screenHeight; } public int getBallWidth() { return mBallWidth; } public int getBallHeight() { return mBallHeight; } public ArrayList<DrawMessage> getMessageList() { return msgArrayList; } public AnimSurfaceView getWindowFlashBall() { return mAnimSurfaceView; } private int _lastX; private int _lastY; public void updataChatBall(MotionEvent event) { if(ToolTipConfig.isUseSurfaceView) { if(null!=mBallDragAnim) { mBallDragAnim.reflesh(event); } } else { int _newlastX=(int) event.getRawX(); int _newlastY=(int) event.getRawY()-getStatusBarHeight(mContext); boolean isDragEnd=(event.getAction()==MotionEvent.ACTION_UP)||(event.getAction()==MotionEvent.ACTION_CANCEL); if(Math.abs(_lastX-_newlastX)>8||Math.abs(_lastY-_newlastY)>8) { _lastX=_newlastX; _lastY=_newlastY; mChatBallParams.x = _lastX-des[0]; mChatBallParams.y = _lastY-des[1]; mWindowManager.updateViewLayout(mChatBall,mChatBallParams); } if(isDragEnd) { _lastX=_newlastX; _lastY=_newlastY; int []src=new int[]{_lastX,_lastY}; final int []des=new int[]{0,0}; _lastX=(_lastX<=(TooltipMgr.getInstance().getScreenWidth())/2)?TooltipMgr.getInstance().getBallWidth()/2:TooltipMgr.getInstance().getScreenWidth()-TooltipMgr.getInstance().getBallWidth()/2; if(_lastY<TooltipMgr.getInstance().getBallHeight()/2) { _lastY=TooltipMgr.getInstance().getBallHeight()/2; } else if(_lastY>TooltipMgr.getInstance().getScreenHeight()-TooltipMgr.getInstance().getBallHeight()/2) { _lastY=TooltipMgr.getInstance().getScreenHeight()-TooltipMgr.getInstance().getBallHeight()/2; } des[0]=_lastX; des[1]=_lastY; if(null!=trimRunnable) { trimRunnable.stopRun(); } trimRunnable=new TransAnimRunnable(src, des,200,new Runnable() { @Override public void run() { mChatBallParams.x = des[0]-TooltipMgr.this.des[0]; mChatBallParams.y = des[1]-TooltipMgr.this.des[1]; mWindowManager.updateViewLayout(mChatBall,mChatBallParams); TooltipMgr.this.src=des; } }); mHandler.post(trimRunnable); } } } public void updateDraggedMessage(MotionEvent event) { if(null!=mMessageDragAnim) { mMessageDragAnim.reflesh(event); } } public boolean isDraggedMessageDelete(MotionEvent event) { if(null!=mMessageDragAnim) { return mMessageDragAnim.isDelete(event); } return false; } private HashMap<String, SoftReference<Bitmap>> cache=new HashMap<String, SoftReference<Bitmap>>(); public Bitmap[] getHeadBitmaps() { int size=Math.min(3, msgArrayList.size()); Bitmap[] ret=new Bitmap[size]; Bitmap bmp; for(int i=0;i<ret.length;i++) { String url=msgArrayList.get(i).msgList.get(0).getAvatar(); SoftReference<Bitmap> ref = cache.get(url); if ( ref != null ) { bmp =ref.get(); if (bmp == null) { cache.remove(url); } else { cache.put(url, new SoftReference<Bitmap>(bmp)); ret[i]=bmp; continue; } } ret[i]=getFromAssetBitmap(msgArrayList.get(i).msgList.get(0).getAvatar()); if(null!=ret[i]) { cache.put(url, new SoftReference<Bitmap>(ret[i])); } } return ret; } public Bitmap getBitmap(String url) { Bitmap bmp=null; SoftReference<Bitmap> ref = cache.get(url); if ( ref != null ) { bmp =ref.get(); if (bmp == null) { cache.remove(url); } else { cache.put(url, new SoftReference<Bitmap>(bmp)); return bmp; } } bmp=getFromAssetBitmap(url); if(null!=bmp) { cache.put(url, new SoftReference<Bitmap>(bmp)); } return bmp; } public Bitmap getFromAssetBitmap(String fileName){ try { return BitmapFactory.decodeStream(mContext.getResources().getAssets().open(fileName)); } catch (Exception e) { e.printStackTrace(); } return null; } @SuppressLint("DefaultLocale") public Bitmap getCircleBitmap(int width,int height) { String url=String.format("image:width:%d_height:%d",width,height); Bitmap bmp=null; SoftReference<Bitmap> ref = cache.get(url); if ( ref != null ) { bmp =ref.get(); if (bmp == null) { cache.remove(url); } else { cache.put(url, new SoftReference<Bitmap>(bmp)); return bmp; } } bmp=makeDst(width, height); if(null!=bmp) { cache.put(url, new SoftReference<Bitmap>(bmp)); } return bmp; } private Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(Color.parseColor("#ffffffff")); c.drawOval(new RectF(0, 0, w, h), p); return bm; } public void updateData(Bundle mBundle) { ChatMsg msg=(ChatMsg)mBundle.getSerializable("data"); boolean isFind=false; for(int i=0;i<msgArrayList.size();i++) { if(msgArrayList.get(i).uid==msg.getFriendId()) { msgArrayList.get(i).msgList.add(msg); msgArrayList.get(i).unReadCount++; isFind=true; break; } } if(!isFind) { DrawMessage dm=new DrawMessage(); dm.msgList.add(msg); dm.uid=msg.getFriendId(); dm.unReadCount++; msgArrayList.add(0,dm); } } public void updateUI(final Context context,final int status,final Bundle mBundle) { Log.v(TAG,"updateUI status:"+status); mHandler.post(new Runnable(){ @Override public void run() { if(status==STATUS_OPEN) { hideChatUI(); hideAnimView(); showChatBall(context); mChatBall.setImageResource(R.drawable.tooltip_icon_f); } else if(status==STATUS_MESSAGE_NULL2FULL) { hideChatUI(); hideAnimView(); showChatBall(context); mChatBall.setImageResource(R.drawable.tooltip_icon_f); } else if(status==STATUS_MESSAGE_ADD) { if(isChatUIAddWindow) { showChatUI(context); } else if(!isChatBallAddWindow) { showChatBall(context); } else if(isChatBallAddWindow) { mChatBall.setImageResource(R.drawable.tooltip_icon_f); if(null!=mVirRunnable) { mVirRunnable.stopRun(); } mVirRunnable=new VirRunnable(); mHandler.post(mVirRunnable); } } else if(status==STATUS_MESSAGE_FULL2NULL) { } else if(status==STATUS_CHATWINDOW_OPEN)//点击小球,开始动画OK { if(ToolTipConfig.isUseSurfaceView) { hideChatBall(); hideChatUI(); IAnimation anim=ToolTipConfig.isAnimWithShadow?new TransAnimShadow(context, src, des, status, 250, getHeadBitmaps()):new TransAnim(context, src, des, status, 300); showAnimView(context, anim); } else { hideChatUI(); if(null!=trimRunnable) { trimRunnable.stopRun(); } trimRunnable=new TransAnimRunnable(src, des,showChatUIRunnable); mHandler.post(trimRunnable); } } else if(status==STATUS_CHATWINDOW_EXPAND)//小球动画完毕,显示聊天窗口 OK { hideChatBall(); hideAnimView(); showChatUI(context); } else if(status==STATUS_CHATWINDOW_DRAWBACK||status==STATUS_CHATWINDOW_DRAWBACK_MESSAGE_NULL)//点击聊天窗口下半部分,收缩 OK { if(ToolTipConfig.isUseSurfaceView) { hideAnimView(); hideChatBall(); hideChatUI(); mChatBall.setImageResource(R.drawable.tooltip_icon_nf); IAnimation anim=ToolTipConfig.isAnimWithShadow?new TransAnimShadow(context, des, src, status, 250, getHeadBitmaps()):new TransAnim(context, des, src, status, 300); showAnimView(context, anim); } else { hideAnimView(); hideChatUI(); showChatBall(mContext); mChatBall.setImageResource(R.drawable.tooltip_icon_nf); if(null!=trimRunnable) { trimRunnable.stopRun(); } trimRunnable=new TransAnimRunnable(des, src,showChatBallRunnable); mHandler.post(trimRunnable); } } else if(status==STATUS_CHATWINDOW_CLOSE)//收缩动画完成,显示原来位置OK { hideChatUI(); hideAnimView(); showChatBall(context); } else if(status==STATUS_BALL_DRAG)//拖动小球OK { hideChatBallInvisible(); hideChatUI(); mBallDragAnim=ToolTipConfig.isAnimWithShadow?new BallDragAnimTail(context, getHeadBitmaps()):new BallDragAnim(context); showAnimView(context, mBallDragAnim); } else if(status==STATUS_BALL_DRAG_END_BALL)//拖动小球结束OK { hideAnimView(); int []_src=mBundle.getIntArray("data");//重置位置 retSettingBall(context, _src); showChatBall(context); } else if(status==STATUS_RECRODING_START) { showMicView(context); } else if(status==STATUS_RECRODING_STOP) { hideMicView(); } else if(status==STATUS_MESSAGE_DRAG)//OK { int []viewLocation=mBundle.getIntArray("data"); String headPath=mBundle.getString("data1"); mMessageDragAnim=new MessageDragAnim(context, getScreenWidth(), getScreenHeight()-getStatusBarHeight(context),viewLocation, getBitmap(headPath)); showAnimView(context, mMessageDragAnim); } else if(status==STATUS_MESSAGE_DRAG_FLASHVIEW_END)//OK { hideAnimView(); } else if(status==STATUS_CLOSE) { closeWindows(); } } }); } private WindowManager.LayoutParams getChatBallParam(Context context) { if(null==mChatBallParams) { /* * params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 通知栏处也可见 * 如果设置为params.type = WindowManager.LayoutParams.TYPE_PHONE; * 那么优先级会降低一些, 即拉下通知栏不可见 */ mChatBallParams=new WindowManager.LayoutParams(); mChatBallParams.type=WindowManager.LayoutParams.TYPE_PHONE; mChatBallParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明 mChatBallParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; mChatBallParams.width=getBallWidth(); mChatBallParams.height=getBallHeight(); mChatBallParams.gravity=Gravity.LEFT| Gravity.TOP; // 调整悬浮窗口至右侧中间 mChatBallParams.x=src[0]-des[0]; mChatBallParams.y=src[1]-des[1]; mChatBallParams.softInputMode=WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; } return mChatBallParams; } private WindowManager.LayoutParams getChatUIParam(Context context) { if(null==mChatUIParams) { mChatUIParams=new WindowManager.LayoutParams(); mChatUIParams.type=WindowManager.LayoutParams.TYPE_PHONE; mChatUIParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明 mChatUIParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; mChatUIParams.width=WindowManager.LayoutParams.MATCH_PARENT; mChatUIParams.height=WindowManager.LayoutParams.MATCH_PARENT; mChatUIParams.gravity=Gravity.LEFT| Gravity.TOP; // 调整悬浮窗口至右侧中间 mChatUIParams.x=0; mChatUIParams.y=0; mChatUIParams.softInputMode=WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; } return mChatUIParams; } private WindowManager.LayoutParams getAnimSurfaceViewParam(Context context) { if(null==mAnimSurfaceViewParams) { mAnimSurfaceViewParams=new WindowManager.LayoutParams(); mAnimSurfaceViewParams.type=WindowManager.LayoutParams.TYPE_PHONE; mAnimSurfaceViewParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明 mAnimSurfaceViewParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; mAnimSurfaceViewParams.width=WindowManager.LayoutParams.MATCH_PARENT; mAnimSurfaceViewParams.height=WindowManager.LayoutParams.MATCH_PARENT; mAnimSurfaceViewParams.gravity=Gravity.LEFT| Gravity.TOP; // 调整悬浮窗口至右侧中间 mAnimSurfaceViewParams.x=0; mAnimSurfaceViewParams.y=0; mAnimSurfaceViewParams.softInputMode=WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; } return mAnimSurfaceViewParams; } private WindowManager.LayoutParams getMicParam(Context context) { if(null==mMicParams) { mMicParams=new WindowManager.LayoutParams(); mMicParams.type=WindowManager.LayoutParams.TYPE_PHONE; mMicParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明 mMicParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; mMicParams.width=context.getResources().getDrawable(R.drawable.tooltip_mic_bottom).getIntrinsicWidth(); mMicParams.height=context.getResources().getDrawable(R.drawable.tooltip_mic_bottom).getIntrinsicHeight(); mMicParams.x = 0; mMicParams.y = 0; mMicParams.softInputMode=WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; } return mMicParams; } private void showChatBall(Context context) { if(null==mChatBall) { mChatBall=new ChatBall(context); } if(null==mChatUI) { mChatUI=new ChatUI(context); } if(mChatBall.getVisibility()!=View.VISIBLE) { mChatBall.setVisibility(View.VISIBLE); } if(!isChatBallAddWindow) { mChatBallParams=getChatBallParam(context); mWindowManager.addView(mChatBall, mChatBallParams); isChatBallAddWindow=true; } } private void showChatUI(Context context) { if(null==mChatUI) { mChatUI=new ChatUI(context); } mChatUI.onUIupdate(); if(!isChatUIAddWindow) { mChatUIParams=getChatUIParam(context); mWindowManager.addView(mChatUI, mChatUIParams); isChatUIAddWindow=true; } } private void showAnimView(Context context,IAnimation anim) { if(null==mAnimSurfaceView) { mAnimSurfaceView=new AnimSurfaceView(context); } if(!isAnimViewAddWindow) { mAnimSurfaceViewParams=getAnimSurfaceViewParam(context); mWindowManager.addView(mAnimSurfaceView, mAnimSurfaceViewParams); isAnimViewAddWindow=true; } mAnimSurfaceView.postAnimation(anim); } private void showMicView(Context context) { if(null==mMicImageView) { mMicImageView=new AudioRecordMicView(context); } mWindowManager.addView(mMicImageView, getMicParam(context)); } private void retSettingBall(Context context,int [] loc) { loc[0]=(loc[0]<=(TooltipMgr.getInstance().getScreenWidth())/2)?TooltipMgr.getInstance().getBallWidth()/2:TooltipMgr.getInstance().getScreenWidth()-TooltipMgr.getInstance().getBallWidth()/2; if(loc[1]<TooltipMgr.getInstance().getBallHeight()/2) { loc[1]=TooltipMgr.getInstance().getBallHeight()/2; } else if(loc[1]>TooltipMgr.getInstance().getScreenHeight()-TooltipMgr.getInstance().getBallHeight()/2) { loc[1]=TooltipMgr.getInstance().getScreenHeight()-TooltipMgr.getInstance().getBallHeight()/2; } mChatBallParams.x=loc[0]-des[0]; mChatBallParams.y= (loc[1]-des[1]); mChatBall.setVisibility(View.VISIBLE); mWindowManager.updateViewLayout(mChatBall,mChatBallParams); isChatBallAddWindow=true; src=loc; } private void hideChatBallInvisible() { mChatBall.setVisibility(View.INVISIBLE); } private void hideChatBall() { if(isChatBallAddWindow) { if(null!=mChatBall) { mWindowManager.removeView(mChatBall); } isChatBallAddWindow=false; } } private void hideChatUI() { if(isChatUIAddWindow) { if(null!=mChatUI) { mWindowManager.removeView(mChatUI); } isChatUIAddWindow=false; } } private void hideAnimView() { if(isAnimViewAddWindow) { if(null!=mAnimSurfaceView) { mWindowManager.removeView(mAnimSurfaceView); } isAnimViewAddWindow=false; } } private void hideMicView() { if(null!=mMicImageView) { mWindowManager.removeView(mMicImageView); mMicImageView=null; } } public void closeWindows() { hideChatBall(); hideChatUI(); hideAnimView(); hideMicView(); mChatBall=null; mChatUI=null; mAnimSurfaceView=null; mMicImageView=null; msgArrayList.clear(); } public void onResume() { if(status.isChatBallAddWindow) { hideChatUI(); hideAnimView(); showChatBall(mContext); } else if(status.isChatUIAddWindow) { hideChatBall(); hideAnimView(); showChatUI(mContext); } else { hideChatUI(); hideAnimView(); if(getMessageList().size()>0) { showChatBall(mContext); } } } public void onPause() { if(isChatBallAddWindow||isChatUIAddWindow||isAnimViewAddWindow) { status.isChatBallAddWindow=isChatBallAddWindow; status.isChatUIAddWindow=isChatUIAddWindow; status.isAnimViewAddWindow=isAnimViewAddWindow; hideChatBall(); hideChatUI(); hideAnimView(); isChatBallAddWindow=false; isChatUIAddWindow=false; isAnimViewAddWindow=false; } } public void onConfigurationChanged() { float oldHPrecent=(float)src[1]/(float)(screenHeight-getStatusBarHeight(mContext)); int tmp=screenWidth; screenWidth=screenHeight; screenHeight=tmp; if(src[0]>getBallWidth()/2)//在右边 { src[0]=screenWidth-getBallWidth()/2; getChatBallParam(mContext).x=src[0]-des[0]; } src[1]=(int)(oldHPrecent*(screenHeight-getStatusBarHeight(mContext))); getChatBallParam(mContext).y=src[1]-des[1]; if(isChatBallAddWindow) { mWindowManager.updateViewLayout(mChatBall,getChatBallParam(mContext)); } Log.v(TAG,"onConfigurationChanged sWidth:"+screenWidth+" sHeight:"+screenHeight); //重新设置Src的值,与parms的值 if(null!=mChatUI) mChatUI.onUIupdate(); } private VirRunnable mVirRunnable; private TransAnimRunnable trimRunnable; private Runnable showChatUIRunnable=new Runnable() { @Override public void run() { hideChatBall(); showChatUI(mContext); } }; private Runnable showChatBallRunnable=new Runnable() { @Override public void run() { if(getMessageList().size()==0) { hideChatBall(); } } }; private TooltipState status=new TooltipState(); public class DrawMessage { public long uid; public ArrayList<ChatMsg> msgList=new ArrayList<ChatMsg>(1); public int unReadCount; } private class TooltipState { public boolean isChatBallAddWindow=false;//小球是否添加了 public boolean isChatUIAddWindow=false;//对话框是否添加了 public boolean isAnimViewAddWindow=false;//动画View是否添加了 } private class VirRunnable implements Runnable { final long end; final int oldX; long run; private int amplitude; public VirRunnable() { end=System.currentTimeMillis()+500; oldX=(mChatBallParams.x=(src[0]<=(getScreenWidth())/2)?0:getScreenWidth()-getBallWidth()); amplitude=DensityUtil.dip2px(mContext, 25); } public void stopRun() { mHandler.removeCallbacks(this); getChatBallParam(mContext).x=oldX; mWindowManager.updateViewLayout(mChatBall,mChatBallParams); } @Override public void run() { if((run=(end-System.currentTimeMillis()))>0) { int value=(int) (amplitude*Math.sin((float)4*Math.PI*(500-run)/(float)500)); if(oldX>0&&value<0||oldX<=0&&value>0) { value=(-value); } getChatBallParam(mContext).x=oldX-value; mWindowManager.updateViewLayout(mChatBall,mChatBallParams); mHandler.postDelayed(this, 20); } else { mHandler.removeCallbacks(this); getChatBallParam(mContext).x=oldX; mWindowManager.updateViewLayout(mChatBall,mChatBallParams); } } } private class TransAnimRunnable implements Runnable { private int dx; private int dy; private int duration=300; private long start; private long runMills=0; private int[] srcLoc; private int[] desLoc; private Runnable run; public TransAnimRunnable(int[] srcLoc, int[] desLoc, Runnable run) { this(srcLoc, desLoc, 300, run); } public TransAnimRunnable(int[] srcLoc, int[] desLoc, int duration ,Runnable run) { this.srcLoc=srcLoc; this.desLoc=desLoc; dx=desLoc[0]-srcLoc[0]; dy=desLoc[1]-srcLoc[1]; start=System.currentTimeMillis(); this.duration=duration; this.run = run; } public void stopRun() { mHandler.removeCallbacks(this); } @Override public void run() { if((runMills=(System.currentTimeMillis()-start))<duration) { int _dx=(int)((float)runMills*dx/(float)duration); int _dy=(int)((float)runMills*dy/(float)duration); mChatBallParams.x = (srcLoc[0]+_dx)-des[0]; mChatBallParams.y = (srcLoc[1]+_dy)-des[1]; mWindowManager.updateViewLayout(mChatBall,mChatBallParams); mHandler.postDelayed(this, 20); } else { mChatBallParams.x = desLoc[0]-des[0]; mChatBallParams.y = desLoc[1]-des[1]; mWindowManager.updateViewLayout(mChatBall,mChatBallParams); if(null!=run) { run.run(); } mHandler.removeCallbacks(this); } } } }
5 、动画特效,请看Demo中的代码
Demo 代码下载地址:http://download.csdn.net/detail/zz7zz7zz/6451837
分享无止境,能分享给大家是我的荣幸,欢迎大家讨论与提意见!
微博:http://weibo.com/u/3209971935