android 超炫的悬浮窗设计与实现

来源:互联网 发布:吉首大学网络缴费系统 编辑:程序博客网 时间:2024/05/29 21:16

现在很多软件都有悬浮框功能,比如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();}


具体的动画见com.open.tooltip.anim包下的具体实现类


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();@Overridepublic 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();@Overridepublic IBinder onBind(Intent arg0) {return null;}@Overridepublic 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();}}@Overridepublic void onDestroy() {Log.v(TAG, "onDestroy");mHandler.removeCallbacks(heartRunnable);super.onDestroy();}@Overridepublic 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() {@Overridepublic 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;}@Overridepublic void onConfigurationChanged(Configuration newConfig) {Log.v(TAG, "onConfigurationChanged()");if(TooltipMgr.getInstance().getScreenWidth()!=TooltipMgr.getInstance().getWindowManager().getDefaultDisplay().getWidth()){TooltipMgr.getInstance().onConfigurationChanged();}super.onConfigurationChanged(newConfig);}}

4.TooltipMgr , 控制悬浮框的具体行为


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() {@Overridepublic 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(){@Overridepublic 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() {@Overridepublic void run() {hideChatBall();showChatUI(mContext);}};private Runnable showChatBallRunnable=new Runnable() {@Overridepublic 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);}@Overridepublic 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);}@Overridepublic 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


分享无止境,能分享给大家是我的荣幸,欢迎大家讨论与提意见!



邮箱:zz7zz7zz@163.com

微博:http://weibo.com/u/3209971935


原创粉丝点击