關(guān)于android 浮動(dòng)窗口的使用淺解

最近項(xiàng)目在搞音頻的小窗口播放(不是類似于音樂播放器的那種高端大氣上檔次的貨),經(jīng)過一系列的掙扎和努力算是搞出和設(shè)計(jì)師要求的效果了


效果如下(不要在意圖片的名字)


搜狗截圖_看圖王.png

就是這么個(gè)小東西,在app內(nèi)外來回跑的那種(原諒我不能用gift,不知道公司讓不讓,相信這么淺白的東西,應(yīng)該都能懂吧...)


看也看了,那就開擼吧

1,寫一個(gè)小窗口的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/ll_layout"
              xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
    >

    <LinearLayout
        android:id="@+id/ll_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/float_window_back"http://.9 圖片
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingLeft="10dp"
        android:paddingRight="10dp">

        <FrameLayout
            android:layout_width="40dp"
            android:layout_height="40dp"
            >


            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:scaleType="centerCrop"
                android:src="@drawable/float_window_img"/>

            <ProgressBar
                android:layout_width="25dp"
                android:layout_height="25dp"
                android:layout_gravity="center"
                android:indeterminateDrawable="@drawable/float_window_anim"/>//動(dòng)畫
        </FrameLayout>


        <TextView
            android:id="@+id/text_room_id"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="8dp"
            android:layout_weight="1"
            android:ellipsize="end"
            android:gravity="center"
            android:singleLine="true"
            android:textColor="#E6E6E6"
            android:textSize="14sp"/>

        <ImageButton
            android:id="@+id/bt_close"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="@color/transparent"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:src="@drawable/float_window_close"
            />
    </LinearLayout>


</LinearLayout>
float_window_anim

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" >
    <item android:drawable="@drawable/float_window_animate_01" android:duration="300"></item>
    <item android:drawable="@drawable/float_window_animate_02" android:duration="300"></item>
    <item android:drawable="@drawable/float_window_animate_03" android:duration="300"></item>
</animation-list>

2,擼一個(gè)小窗口的自定義View

public class FloatWindowView extends LinearLayout implements View.OnClickListener {
    private final TextView text_room_id;
    public final ImageButton bt_close;
    private WindowManager mManager;
    private Context mContext;
    private WindowManager.LayoutParams mParams;

    public FloatWindowView(Context context) {
        super(context);
        mContext = context;
        mManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        LayoutInflater.from(context).inflate(R.layout.dialog_video_play, this);
        text_room_id = (TextView) findViewById(R.id.text_room_id);
        bt_close = (ImageButton) findViewById(R.id.bt_close);
        bt_close.setOnClickListener(this);
    }
    
//外部傳入LayoutParams 
    public void setParams(WindowManager.LayoutParams params) {
        this.mParams = params;
    }

    int lastX, lastY;
    int paramX, paramY;
    boolean isMove;

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                paramX = mParams.x;
                paramY = mParams.y;
                break;
            case MotionEvent.ACTION_MOVE:

                int dx = (int) event.getRawX() - lastX;
                int dy = (int) event.getRawY() - lastY;
                if (Math.abs(dx) >= 50 || Math.abs(dy) >= 50) {
                    isMove = true;
                }
                mParams.x = paramX + dx;
                mParams.y = paramY + dy;
                mManager.updateViewLayout(this, mParams);
                break;
            case MotionEvent.ACTION_UP:
                if (!isMove) {
                    int x = (int) event.getRawX() - lastX;
                    int y = (int) event.getRawY() - lastY;
                    if (Math.abs(x) <= 50 || Math.abs(y) <= 50) {
                        //模擬點(diǎn)擊事件
                      doClick();
                    }
                }
                isMove = false;
                break;
        }
        return true;

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_close:
               //關(guān)閉窗口,服務(wù)之類的東東
                break;
        }
    }
    
}
這里有個(gè)插曲,我們不能給整個(gè)小窗口的根布局設(shè)置點(diǎn)擊事件,這樣的話 mManager.updateViewLayout(this, mParams);更新小窗口位置的事件就會(huì)被攔截,導(dǎo)致小窗口不能跟著手指滑動(dòng),因此用了個(gè)粗鄙的辦法模擬點(diǎn)擊事件了
```基于我們項(xiàng)目的實(shí)現(xiàn)方式,我就直接說我們的方式了

3,在Application中創(chuàng)建,顯示并記錄小窗口的顯示狀態(tài)

//顯示狀態(tài)表示
 public boolean inWindowShowing = false;
 private FloatWindowView mFloatWindowView;

    public void createFloatView(Context context) {
        if (null == mFloatWindowView) {
            mFloatWindowView = new FloatWindowView(context);
//獲取窗體服務(wù)
            WindowManager wm = (WindowManager) getSystemService(
                    Context.WINDOW_SERVICE);
//創(chuàng)建一個(gè)窗體布局參數(shù)
            WindowManager.LayoutParams params = new WindowManager.LayoutParams();
//保證背景無色
            params.format = PixelFormat.TRANSPARENT;
//設(shè)置窗體初始化的位置(這個(gè)很糾結(jié),下文再講)
            params.gravity = Gravity.CENTER_VERTICAL;
            params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            params.width =WindowManager.LayoutParams.WRAP_CONTENT;
            params.height =WindowManager.LayoutParams.WRAP_CONTENT;
//x坐標(biāo)的位置(這個(gè)是在gravity的基礎(chǔ)上的)
            params.x= wm.getDefaultDisplay().getWidth()/2;
//y坐標(biāo)位置
            params.y=wm.getDefaultDisplay().getHeight()/2- UIUtils.dip2px(100);
//這個(gè)標(biāo)識(shí)的優(yōu)先級(jí)低于下拉通知欄
                params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
//這個(gè)就高于了  不推薦使用
//                params.type = WindowManager.LayoutParams.TYPE_PHONE;


        /*
         * 下面的flags屬性的效果形同“鎖定”约巷。 懸浮窗不可觸摸姓蜂,不接受任何事件,同時(shí)不影響后面的事件響應(yīng)。
         * wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL |
         * LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE;
         */
//先給浮窗view設(shè)置參數(shù),方便滑動(dòng)時(shí)動(dòng)態(tài)改變小窗口位置
            mFloatWindowView.setParams(params);
           //添加到窗體上
            wm.addView(mFloatWindowView, params);
//顯示標(biāo)識(shí)
            inWindowShowing = true;
        }

    }
//這個(gè)很簡(jiǎn)單,從窗體上移除
    public void reMoveFloatView() {
        if (null != mFloatWindowView) {
            WindowManager wm = (WindowManager) getSystemService(
                    Context.WINDOW_SERVICE);
            wm.removeView(mFloatWindowView);
            mFloatWindowView = null;
            inWindowShowing = false;
        }
    }
#然而然而然而,這個(gè)小窗口的初始化位置可把我整的夠嗆,只要把gravity設(shè)置成TOP和LEFT,
#好的可以就是在屏幕的左上角了(當(dāng)然設(shè)置成CENTER就會(huì)居中),但是呢  我們的設(shè)計(jì)說要在界面的右下角
#并且距離底部導(dǎo)航欄高個(gè)20px,那么問題就來了  我把gravity設(shè)置成RIGHT|BOTTOM不就行了?NONONO,
#TOO羊TOO新坡,設(shè)置成Bottom  只能在底部移動(dòng)了就,  設(shè)置成Right和Bottom那么就直接不能動(dòng)了,
#所以才有了設(shè)置成CENTER_VERTICAL,這個(gè)位置的的X和Y都是相對(duì)于屏幕的中間的,
#所以讓浮窗顯示在右邊就把X設(shè)置成屏幕的一半,下邊就把Y設(shè)置成高度的一半加上導(dǎo)航欄的高度再加個(gè)20px,好吧 位置終于OK 了

這樣的話就差不多實(shí)現(xiàn)了小窗口了

關(guān)于那些個(gè)FLOG的什么意思的直接看這個(gè) 傳送門--TP


到此我們可以安安靜靜的寫寫文章泡泡X了,可是.....................

TMD的一些國(guó)產(chǎn)ROM默認(rèn)是把浮窗的權(quán)限是關(guān)著的...........我曹.....

不過不要慌 還好前輩們幫我們解決了這個(gè)問題(至少90%吧)

4,浮窗權(quán)限的適配

具體做法傳送門--TP

再次向前輩們致敬...........

這個(gè)實(shí)現(xiàn)方式目前是有缺陷的,最好能在service中創(chuàng)建,這樣不容易被系統(tǒng)回收,反正問題還是有得,歡迎大家在評(píng)論區(qū)點(diǎn)評(píng)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末忠聚,一起剝皮案震驚了整個(gè)濱河市赂蕴,隨后出現(xiàn)的幾起案子觉至,更是在濱河造成了極大的恐慌,老刑警劉巖睡腿,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件语御,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡席怪,警方通過查閱死者的電腦和手機(jī)应闯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挂捻,“玉大人碉纺,你說我怎么就攤上這事】倘觯” “怎么了骨田?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)声怔。 經(jīng)常有香客問我态贤,道長(zhǎng),這世上最難降的妖魔是什么醋火? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任悠汽,我火速辦了婚禮,結(jié)果婚禮上芥驳,老公的妹妹穿的比我還像新娘柿冲。我一直安慰自己,他們只是感情好兆旬,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布假抄。 她就那樣靜靜地躺著,像睡著了一般丽猬。 火紅的嫁衣襯著肌膚如雪宿饱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天宝鼓,我揣著相機(jī)與錄音刑棵,去河邊找鬼。 笑死愚铡,一個(gè)胖子當(dāng)著我的面吹牛蛉签,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沥寥,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼碍舍,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了邑雅?” 一聲冷哼從身側(cè)響起片橡,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎淮野,沒想到半個(gè)月后捧书,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吹泡,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年经瓷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了爆哑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出和橙,到底是詐尸還是另有隱情乏屯,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏屯换。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一伶氢、第九天 我趴在偏房一處隱蔽的房頂上張望趟径。 院中可真熱鬧,春花似錦癣防、人聲如沸蜗巧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)幕屹。三九已至,卻和暖如春级遭,著一層夾襖步出監(jiān)牢的瞬間望拖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工挫鸽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留说敏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓丢郊,卻偏偏與公主長(zhǎng)得像盔沫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枫匾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,506評(píng)論 25 707
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程架诞,因...
    小菜c閱讀 6,358評(píng)論 0 17
  • 繁華過謙,都迷途在了金錢利益堆積的虛榮里干茉。在這個(gè)你騙我我騙你的社會(huì)谴忧,哪還有什么最純的愛,哪還有最真摯的感情。這些...
    地窖里的白菜閱讀 240評(píng)論 0 1
  • 每個(gè)人的一生都如同一次秋天争涌,都會(huì)經(jīng)歷落花,敗葉的過程辣恋。但有的人蛻變成為了天鵝;而有的人卻一敗涂地模软;在我們的年華中伟骨,...
    崔伊萌閱讀 455評(píng)論 1 0
  • 你總覺得人有壓力才會(huì)進(jìn)步携狭,人有壓力是會(huì)進(jìn)步?jīng)]錯(cuò),不過也是因人而已的回俐,壓力對(duì)于心理承受能力強(qiáng)的人逛腿,可能會(huì)是進(jìn)步的動(dòng)力...
    Dhchfuc閱讀 585評(píng)論 0 0