android WindowManager实现悬浮窗口

1,用途:

    显示在界面底部提示后台的操作进度.比如下载进度.

2,原理:

    (1)将提示界面以TYPE_SYSTEM_ALERT,TYPE_SYSTEM_OVERLAY的形式加入到WindowManager中,从而实现全局的悬浮窗口.

(2)创建一个Activity作为所有activity的基类,在onResume时显示悬浮窗口,在onPause里移除悬浮窗口.这样当应用退出或被其他应用覆盖时,悬浮窗口会消失,从而实现悬浮窗口被自己的应用拥有的效果.

3,不足:

    界面切换时会出现短暂的消失.

4,代码简析:

主要的方法:

(1) public static FloatingBargetInstance(Context c)

本类被设计成单例模式,也就是只有一个实例,方便管理.

(2) protected void onDraw(Canvascanvas)

绘制界面

(3) public void show()

显示悬浮框

(4) public void dismiss()

隐藏悬浮框

(5) public static booleanneedFloatingBar()

是否要显示

5,截图


6,代码

import java.util.List;

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.Paint.FontMetrics;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.Log;
import android.view.Gravity;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.TextView;

public class FloatingBar extends TextView
{
    private final static String TAG = "FloatingBar";
    
    private String mText;
    
    private int mTextSize;
    
    private int mBarHeight;
    
    private int mBarWidth;
    
    private int mIconPadding;
    
    private Bitmap mIcon;
    
    private static Context mContext;
    
    private Paint mPaint;
    
    private Rect mIconSrcRect;
    
    private Rect mIconDestRect;
    
    private Rect mBgSrcRect;
    
    private Rect mBgDestRect;
    
    private float mTextStartX;
    
    private float mTextStartY;
    
    private static FloatingBar mInstance = null;
    
    private Bitmap mBgBmp = null;
    
    public static FloatingBar getInstance(Context c)
    {
        if (mInstance == null)
        {
            mInstance = new FloatingBar(c, R.drawable.ic_launcher, "I am a floating bar");
        }
        return mInstance;
    }
    
    private WindowManager mWindowManager;
    
    /**
     * <创建进度提示框>
     * <进度框显示在屏幕最下方,由应用图标和进度信息组成。>
     * @param context 上下文
     * @param resId 应用图标资源id
     * @param text 下载或安装进度信息
     */
    public FloatingBar(Context context, int resId, String text)
    {
        super(context);
        mContext = context;
        mText = text;
        mIcon = BitmapFactory.decodeResource(mContext.getResources(), resId);
        
        updateIconInfo();
    }
    
    /**
     * <创建进度提示框>
     * <进度框显示在屏幕最下方,由应用图标和进度信息组成。>
     * @param context 上下文
     * @param appIcon 应用图标位图资源
     * @param text 下载或安装进度信息
     */
    public FloatingBar(Context context, Bitmap appIcon, String text)
    {
        super(context);
        mContext = context;
        mText = text;
        mIcon = appIcon;
        
        updateIconInfo();
        
    }
    
    /**
     * <设置应用图标>
     * @param drawable 应用图标资源id
     * @see [类、类#方法、类#成员]
     */
    public void setDrawable(int drawable)
    {
        mIcon = BitmapFactory.decodeResource(mContext.getResources(), drawable);
        updateIconInfo();
        
        invalidate();
    }
    
    /**
     * <设置应用图标>
     * @param appIcon 应用图标位图资源
     * @see [类、类#方法、类#成员]
     */
    public void setDrawable(Bitmap appIcon)
    {
        mIcon = appIcon;
        updateIconInfo();
        
        invalidate();
    }
    
    /**
     * <设置进度信息>
     * @param text 下载、安装进度信息
     * @see [类、类#方法、类#成员]
     */
    public void setMsg(String text)
    {
        this.mText = text;
        
        invalidate();
    }
    
    /**
     * <设置进度框高度>
     * @param h 进度框高度
     * @see [类、类#方法、类#成员]
     */
    public void setBarHeight(int h)
    {
        mBarHeight = h;
        invalidate();
    }
    
    /**
     * <设置进度信息字体大小>
     * @param size 字体大小
     * @see [类、类#方法、类#成员]
     */
    public void setMsmgTextSize(int size)
    {
        mTextSize = size;
        mPaint.setTextSize(size);
        invalidate();
    }
    
    @Override
    protected void onDraw(Canvas canvas)
    {
        // TODO Draw item on the floating bar  
        super.onDraw(canvas);
        canvas.drawBitmap(mBgBmp, mBgSrcRect, mBgDestRect, mPaint);
        canvas.drawBitmap(mIcon, mIconSrcRect, mIconDestRect, mPaint);
        canvas.drawText(mText, mTextStartX, mTextStartY, mPaint);
    }
    
    /**
     * <显示进度框>
     * <在调用dismiss方法移除进度框之前,进度框将一直显示在屏幕最下方。>
     * @see [类、类#方法、类#成员]
     */
    public void show()
    {
        if (!isShown())
        {
            WindowManager.LayoutParams params = new WindowManager.LayoutParams();
            params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT | WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
            params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
            
            params.width = WindowManager.LayoutParams.FILL_PARENT;
            params.height = mBarHeight;
            params.alpha = 80;
            params.format = PixelFormat.RGBA_8888;
            params.gravity = Gravity.LEFT | Gravity.BOTTOM;
            params.x = 0;
            params.y = 0;
            this.setBackgroundColor(Color.BLACK);
            mWindowManager.addView(this, params);
        }
    }
    
    /**
     * <移除进度框>
     * @see [类、类#方法、类#成员]
     */
    public void dismiss()
    {
        if (this.isShown())
        {
            mWindowManager.removeView(this);
        }
    }
    
    /**
     * <在更新应用图标后重新计算关于位图的参数>
     * @see [类、类#方法、类#成员]
     */
    private void updateIconInfo()
    {
        mPaint = new Paint();
        mPaint.setColor(Color.WHITE);
        mPaint.setTextSize(mTextSize);
        mPaint.setTypeface(Typeface.DEFAULT_BOLD);
        
        mWindowManager =
            (WindowManager)getContext().getApplicationContext().getSystemService(getContext().WINDOW_SERVICE);
        mBarWidth = mWindowManager.getDefaultDisplay().getWidth();
        mBarHeight = 65;
        mTextSize = 30;
        mIconPadding = 10;
        
        float textW = mPaint.measureText(mText);
        FontMetrics fm = mPaint.getFontMetrics();
        float textH = fm.descent - fm.ascent;
        Log.d(TAG, "archer text height = " + textH + " text=" + mText);
        float iconW = mBarHeight - 2 * mIconPadding;
        float iconStartX = (mBarWidth - mBarHeight - textW) / 2;
        float iconStartY = mIconPadding;
        mTextStartX = iconStartX + iconW + mIconPadding;
        mTextStartY = (mBarHeight + textH) / 2; // The position of the bottom of text.
        
        mIconSrcRect = new Rect(0, 0, mIcon.getWidth(), mIcon.getHeight());
        mIconDestRect =
            new Rect((int)iconStartX, (int)iconStartY, (int)(iconStartX + iconW), (int)(iconStartY + iconW));
        
        mBgBmp = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.app_detail_download_install_bg);
        
        mBgSrcRect = new Rect(0, 0, mBgBmp.getWidth(), mBgBmp.getHeight());
        mBgDestRect = new Rect(0, 0, mBarWidth, mBarHeight);
    }
    
    /**
     * 判断当前是否需要进度框。
     * @return true 需要进度框 ;false 不需要进度框。
     */
    public static boolean needFloatingBar()
    {
        // return
    }
}

定义FloatingBarActivity,作为其他activity的基类


public class FloatingBarActivity extends Activity implements DownloadStateListener
{
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        
    }
    
    @Override
    protected void onPause()
    {
        super.onPause();
        FloatingBar.getInstance(this).dismiss();
    }
    
    @Override
    protected void onResume()
    {
        super.onResume();
        if (FloatingBar.needFloatingBar())
        {
            FloatingBar.getInstance(this).show();
        }
    }
}




你可能感兴趣的:(android,app)