android 按鍵會觸發ontouch嗎?_Android實現炫酷的拖拽浮動按鈕

IOS的Assistive Touch效果很炫酷,可以任意拖拽,同時點擊后會展開菜單欄。然而,這不只是IOS的特權,Android也可以實現。但是由于懸浮窗需要申請權限,所以本文僅在app內實現,可以任意拖拽,并可以響應點擊事件。

一、效果圖

d61acc6048bdcd0d33d2cf771608056b.gif

效果還是不錯的。上圖看出雖然沒有像IOS一樣彈出菜單欄,僅僅以Toast和旋轉動畫的效果代替了(因為太懶了,更炫酷的效果交給你們的想象了)。但是確實支持點擊事件,并且和拖拽事件不沖突。

二、實現原理

1、拖拽實現

很簡單,設置TouchListener監聽,實現onTouch方法,在ACTION_MOVE的過程中隨著x,y坐標的移動更新浮動按鈕的位置。下面具體介紹重寫onTouch方法的具體實現監聽ACTION_DOWN事件
case MotionEvent.ACTION_DOWN:{                mDownPointerId = MotionEventCompat.getPointerId(event, 0);                mPreviousX = event.getRawX();                mPreviousY = event.getRawY();                break;            }
記錄初始的坐標以及觸摸點。監聽ACTION_MOVE事件
case MotionEvent.ACTION_MOVE:{                if (mDownPointerId >= 0) {                    int index = MotionEventCompat.getActionIndex(event);                    int id = MotionEventCompat.getPointerId(event, index);                    if (id == mDownPointerId) {                        boolean update = adjustMarginParams(view, event);                        if (!update) {                            break;                        }                        mFloatView.requestLayout();                        mHasMoved = true;                        result = true;                    }                }                break;            }
其中最重要的是adjustMarginParams(view, event)方法,來更新浮動按鈕的相對位置。
private boolean adjustMarginParams(View v, MotionEvent event) {        float x =  event.getRawX();        float y =  event.getRawY();        float deltaX = x - mPreviousX;        float deltaY = y - mPreviousY;        if (!mHasMoved) {            if (Math.abs(deltaX) < mTouchSlop && Math.abs(deltaY) < mTouchSlop) {                return false;            }        }        //左上角位置        int newX = (int)x - mFloatView.getWidth() / 2;        int newY = (int)y - mFloatView.getHeight() / 2;        newX = Math.max(newX, mBoundsInScreen.left + mEdgePaddingLeft);        newX = Math.min(newX, mBoundsInScreen.right - mEdgePaddingRight - mFloatView.getWidth());        newY = Math.max(newY, mBoundsInScreen.top + mEdgePaddingTop);        newY = Math.min(newY, mBoundsInScreen.bottom - mEdgePaddingBottom - mFloatView.getHeight());        mFloatViewWindowParam.x = newX;        mFloatViewWindowParam.y = newY - mParentMarginTop;        return true;    }
其中mBoundsInScreen代表浮動按鈕可移動的矩形范圍。根據當前event內的坐標與mBoundsInScreen范圍比較,選擇最終拖拽到達的位置,設置給浮動按鈕的布局參數mFloatViewWindowParam,然后調用requestLayout更新布局。監聽ACTION_UP/ACTION_CANCEL
case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:{                if (mDownPointerId >= 0 && mHasMoved) {                    event.setAction(MotionEvent.ACTION_CANCEL);                    adjustMarginParams(view, event);                    mFloatView.requestLayout();                    int center = (mBoundsInScreen.width() - mFloatView.getWidth()) / 2;                    int x = mFloatViewWindowParam.x;                    int destX = 0;                    int posX = Gravity.LEFT;                    //抬起時 根據位置強制把浮動按鈕歸于左邊或右邊                    if (x < center) { // 左邊                        destX = mBoundsInScreen.left + mEdgePaddingLeft;                    } else {                        posX = Gravity.RIGHT;                        destX = mBoundsInScreen.right - mEdgePaddingRight - mFloatView.getWidth();                    }                    if (mFloatButtonCallback != null) {                        float posY = 0;                        if (mBoundsInScreen.height() - mFloatView.getHeight() != 0) {                            posY = 1f * (mFloatViewWindowParam.y - mBoundsInScreen.top) / (mBoundsInScreen.height() - mFloatView.getHeight());                        }                        mFloatButtonCallback.onPositionChanged(destX, mFloatViewWindowParam.y, posX, posY);                    }                    int deltaHorizon = destX - x;                    //小于100直接移動 否則開啟動畫                    if (Math.abs(deltaHorizon) < 100) {                        mFloatViewWindowParam.x = destX;                        mFloatView.requestLayout();                    } else {                        ValueAnimator animator = ValueAnimator.ofInt(x, destX);                        animator.setInterpolator(mInterpolator);                        if (mUpdateListener == null) {                            mUpdateListener = new FloatAnimatorUpdateListener();                            mUpdateListener.setUpdateView(FloatTouchListener.this);                        }                        animator.addUpdateListener(mUpdateListener);                        animator.setDuration(200);                        animator.start();                    }                }                resetStatus();                break;            }        }
實現當抬起的瞬間,根據當前所處坐標靠左還是靠右,把浮動按鈕置于左邊緣或者右邊緣。同時,調用回調,把移動相對位置傳給回調函數,實現拖拽監聽。當從當前位置移動到左/右邊緣的距離小于100時,直接移動,否則實現動畫減速移動效果。如此簡單便可實現任意拖拽的效果了,具體一些細節要細看源碼實現。

2.點擊實現

也許有人會認為點擊事件很好實現啊,setOnClickListener()設置個監聽就可以實現了。不信你去試試,沒用。其實點擊實現才是本篇文章的精髓,因為靈活應用到了事件分發機制。從事件分發機制中我們知道,就優先級而言:onTouchListener>onClickListenr。上面的拖拽事件已經消費了onTouchListener(即onTouch方法中返回true),那么就不會下發到onClickListenr,自然就不會產生點擊事件。也許你想讓onTouchListener不消費,然后不就下發到onClickListenr了么?確實這樣可以實現點擊事件,但是拖拽功能又實現不了了。因為onTouch方法中返回false,確實onClickListenr接收到了事件,然后消費掉。可是因為onTouch方法中返回false,所以接下來的一切事件不能接受,沒辦法響應拖拽效果了。通過上面的分析,最終的解決辦法就是:onTouch方法中,在接收到ACTION_DOWN后,返回false,交給onClickListenr處理。剩下的ACTION_MOVE/ACTION_UP等事件,返回true,交給onTouchListener處理,這樣自然就可以既實現拖拽效果又實現點擊效果了。具體實現以下面偽代碼為例
  public boolean onTouch(View view, MotionEvent event) {        int action = MotionEventCompat.getActionMasked(event);        if (mFloatButtonCallback != null) {            mFloatButtonCallback.onTouch();        }        boolean result = false;        switch (action) {            case MotionEvent.ACTION_DOWN:{               ....................................................                break;            }            case MotionEvent.ACTION_MOVE:{               ....................................................                result = true;                break;            }            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:{                ................................................                break;            }        }        return result;    }
原理就是這么簡單,更加炫酷的效果可自定義實現源碼地址:https://github.com/LRH1993/FloatingDragButton到這里就結束啦往期精彩回顧:
  • Android實現短信驗證碼自動填充功能

  • Android仿echo精美彈幕功能

  • Android實現頭像重疊排列功能

  • Android仿QQ個性標簽功能

  • Android仿QQ側滑刪除的功能

b9742a82b0df76e6089e40ad83f5c8c5.png

1e8ec0cca67ae297755fbed7c1f72f52.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/455532.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/455532.shtml
英文地址,請注明出處:http://en.pswp.cn/news/455532.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

強名稱程序集(strong name assembly)——為程序集賦予強名稱

引言&#xff1a;在曾經的項目開發中&#xff0c;在程序集中見到過一個后綴為*.snk的文件。當時看這個文件的圖標。感覺可能是企業內部保護版權啥的一種方式。一&#xff0c;強程序集攻克了哪些問題&#xff1f;1&#xff0c;唯一標識一個程序集2&#xff0c;放置程序集被仿冒和…

如何成為一名合格的數據分析師

“21世紀什么最貴&#xff0c;人才”&#xff0c;在目前大數據時代下&#xff0c;什么最難找&#xff0c;什么最貴&#xff0c;實現數據價值的人&#xff0c;數據分析師。 但是對于數據分析師的認識&#xff0c;比較極端&#xff0c;但對數據分析師價值的認識正在回歸理性。很多…

【ffmpeg for wince】音視頻編解碼多平臺移植(for window/wince))ffmpeg

from: http://www.cnblogs.com/windwithlife/archive/2009/05/31/1492728.html 終于完成了了第二個Client side原型&#xff08;for Wince)&#xff0c;其中花掉我最多時間的就是ffmpeg的對WINCE的移植。其中有大半時間是由于網上的一些不完整及不正確信息所誤導&#xff0c;但…

Java 重寫(Override)與重載(Overload)

重寫(Override) 重寫是子類對父類的允許訪問的方法的實現過程進行重新編寫&#xff01;返回值和形參都不能改變。即外殼不變&#xff0c;核心重寫&#xff01; 重寫的好處在于子類可以根據需要&#xff0c;定義特定于自己的行為。也就是說子類能夠根據需要實現父類的方法。在面…

銀聯pos小票word模板_商家pos機刷卡必須知道的知識

相信很多卡友伙伴或者商鋪店家都裝有pos機&#xff0c;然后一般pos機都沒有使用說明書&#xff0c;更沒有結合刷卡方法在內的秘籍。今天我就分享下刷卡必須知道的一些知識。剛剛辦理pos機的當天一定要注意&#xff1a;使用之前呢&#xff0c;務必核對一下基本信息&#xff0c;例…

《Ext JS權威指南》——2.4節關于Ext.onReady

2.4 關于Ext.onReady 代碼為什么寫在Ext.onReady中&#xff0c;而不是在body中添加一個onload事件并在onload事件中運行呢&#xff1f;主要原因是Ext.onReady在DOM模型加載完畢后即可進行操作&#xff0c;而無需像onload事件那樣&#xff0c;等待頁面的所有資源都加載完畢后才…

git push 提交時顯示 Empty reply from server的解決辦法

輸入 git fetch origin --prune 參考鏈接&#xff1a;https://stackoverflow.com/questions/28364023/gits-error-on-push-empty-reply-from-server 轉載于:https://www.cnblogs.com/team42/p/6941678.html

轉]移動視頻監控(1)---項目綜述

對于市場上的視頻監控系統&#xff0c;大家都有一定的了解&#xff0c;就是視頻采集&#xff0c;經過無線/有線發送到服務或代理&#xff0c;客戶從服務或代理上得到視頻/音頻流。不復雜。 對于不遠的將來&#xff0c;3G&#xff0c;4G的到來&#xff0c;對移動的業務有一個推動…

java 空接口_學Java,java接口搞明白了嗎?大牛讓你一文搞清楚

前言對于面向對象編程來說&#xff0c;抽象是一個極具魅力的特征。如果一個程序員的抽象思維很差&#xff0c;那他在編程中就會遇到很多困難&#xff0c;無法把業務變成具體的代碼。在 Java 中&#xff0c;可以通過兩種形式來達到抽象的目的&#xff0c;一種是抽象類&#xff0…

Check Point CEO:“我們正在積極尋找收購目標”

Check Point Sofrware Technologies很可能成為下一個會產生收購案的主流安全廠商&#xff0c;首席執行官Gil Shwed在該公司第二季度財報電話會議上這樣表示。 “我們正在積極地尋求收購目標&#xff0c;期待無論是大規模的還是小規模的擴張&#xff0c;”Shwed表示。“我們在并…

Spark SQL 編程API入門系列之SparkSQL數據源

不多說&#xff0c;直接上干貨&#xff01; SparkSQL數據源&#xff1a;從各種數據源創建DataFrame 因為 spark sql&#xff0c;dataframe&#xff0c;datasets 都是共用 spark sql 這個庫的&#xff0c;三者共享同樣的代碼優化&#xff0c;生成以及執行流程&#xff0c;所以 s…

H.264中的一些易混淆概念

Q:PSNR 峰值信噪比 Q:是根據它來取qp是不是&#xff1f; A:不是, 和QP沒有直接關系, 但是QP的選擇會影響到PSNR Q: 如果不用率失真最優化&#xff0c; 為什么選擇SATD&#xff0b;deltar&#xff08;mv&#xff0c;mode&#xff09;作為模式選擇的依據&#xff1f;為什么運…

Java中final關鍵字的幾種用法

在java的關鍵字中&#xff0c;static和final是兩個我們必須掌握的關鍵字。不同于其他關鍵字&#xff0c;他們都有多種用法&#xff0c;而且在一定環境下使用&#xff0c;可以提高程序的運行性能&#xff0c;優化程序的結構。下面我們來了解一下final關鍵字及其用法。 final關鍵…

python pyqt5安裝_Python3 安裝PyQt5及exe打包圖文教程

環境: Python 3.6.4 Pycharm Professional 2017.3.3 PyQt5 PyQt5-tools① Python 3 安裝Python 3.x 安裝時&#xff0c;默認勾選ADD Python 3.6 to PATH和ADD Python to environment variables的情況下&#xff0c;系統會向path中增加以下兩個環境變量。D:\Program Files\Py…

《企業軟件交付:敏捷與高效管理精要》——3.4 企業軟件交付的軟件工廠方法...

3.4 企業軟件交付的軟件工廠方法 正如我們前面討論的&#xff0c;今天的機構面對的商業環境正以前所未有的速度發生變化。與此同時&#xff0c;這些機構還要管理和降低整個機構的運營成本。這就直接意味著&#xff0c;他們不僅要最大限度地減少浪費和低效率&#xff0c;還要提…

201706問題記錄

1.四周陰影 box-shadow:0px 0px 10px #f5f5f5; 2. 原生setattribute()方法 jquery的attr()$(.fd-sq-zk).attr("title","收起"); 3.在iframe中獲取外層容器的元素 屬性等 $(parent.document).find("html")..... 4.監聽頁面變大變小事件 /…

一致性hash算法_(圖文案例)一致性哈希算法詳解 一點課堂(多岸教育)

一致性Hash算法關于一致性Hash算法&#xff0c;在我之前的博文中已經有多次提到了&#xff0c;MemCache超詳細解讀一文中”一致性Hash算法”部分&#xff0c;對于為什么要使用一致性Hash算法、一致性Hash算法的算法原理做了詳細的解讀。算法的具體原理這里再次貼上&#xff1a;…

《HTML5 Canvas游戲開發實戰》——2.1 繪制基本圖形

本節書摘來自華章計算機《HTML5 Canvas游戲開發實戰》一書中的第2章&#xff0c;第2.1節,作者&#xff1a;張路斌著&#xff0c; 更多章節內容可以訪問云棲社區“華章計算機”公眾號查看。 2.1 繪制基本圖形 所謂基本圖形&#xff0c;就是指線、矩形、圓等最簡單的圖形&#x…

如何查看Ubuntu版本

有時候需要查看一下系統安裝的Ubuntu的版本&#xff0c;最簡單的方式是輸入lsb_release -a。whatis lsb_release輸出&#xff1a;print distribution-specific information。所以lsb_release這個命令就是用來輸出發行版的信息的。 Open the Terminal enter:lsb_release -a It w…

linux下.a/.so/.la目標庫區別

在linux平臺上編譯時&#xff0c;常會遇到目標庫的疑問&#xff0c;有靜態庫也有動態庫&#xff0c;單個理解都不太難&#xff0c;但是對復雜的工程而言&#xff0c;一旦混合到一起去&#xff0c;對整個工程的理解和調用&#xff0c;將會造成很大困擾&#xff0c;本文就匯總這幾…