記錄貼1:可拖動(dòng),可吸附側(cè)面的懸浮控件

主要功能項(xiàng):
1. 可以拖動(dòng)
2. 拖動(dòng)完可以自動(dòng)貼邊
3. 可處理點(diǎn)擊事件 
4. 可變化背景圖(美術(shù)改圖,棄之不用啊,可惜可惜)
   4.1 吸附左邊的時(shí)候,背景為左邊直角右邊圓角的矩形
   4.2 吸附右邊的時(shí)候,背景為右邊直角左邊圓角的矩形
   4.3 移動(dòng)的時(shí)候,背景為圓角的矩形

第一步.上代碼

class FloatView(context: Context, attributeSet: AttributeSet) :
    RelativeLayout(context, attributeSet) {

    private val MORE_SPACE = 10.0 //移動(dòng)距離像素,超過才算移動(dòng)
    private var mView: View? = null

    init {
        mView = LayoutInflater.from(context).inflate(R.layout.layout_float_view, this, true)

        val rotation = ObjectAnimator.ofFloat(mView?.iv_playing_bg, "rotation", 0f, 360f)
        rotation.duration = 15000
        rotation.repeatCount = -1
        rotation.start()
        val scaleX = ObjectAnimator.ofFloat(mView?.iv_playing_bg, "scaleX", 0.5f, 1f, 0.5f)
        scaleX.duration = 15000
        scaleX.repeatCount = -1
        scaleX.start()
        val scaleY = ObjectAnimator.ofFloat(mView?.iv_playing_bg, "scaleY", 0.5f, 1f, 0.5f)
        scaleY.duration = 15000
        scaleY.repeatCount = -1
        scaleY.start()
    }
    
    //控件的寬高
    private var mWidth = 0
    private var mHeight = 0
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mWidth = w
        mHeight = h
    }

    //屏幕寬高以及半屏和上下邊距
    private var mScreenWith = 0
    private var mScreenHeight = 0
    private var halfWith = 0
    private var mTop = 0
    private var mBottom = 0

    /**
     * 設(shè)置父布局的大小
     */
    fun setParentSize(width: Int, height: Int, top: Int, bottom: Int) {
        mScreenWith = width
        mScreenHeight = height
        halfWith = width / 2

        mTop = top
        mBottom = bottom
    }

    private var lastX = 0f //按下x
    private var lastY = 0f //按下y
    private var isMove = false //是拖動(dòng)?
    private var isPress = false //是點(diǎn)擊?
    private var offsetX = 0f  //偏移量x,移動(dòng)的時(shí)候不加偏移量,按鈕會(huì)發(fā)生位置錯(cuò)誤,手指下會(huì)是按鈕的左上角,而不是最初按下位置
    private var offsetY = 0f //偏移量y
    private var isChangeBg = false //吸邊的時(shí)候可以更改變化按鈕的左右兩邊圓角,后面美術(shù)改了個(gè)方圖,不用了,但思路留在這

    override fun onTouchEvent(ev: MotionEvent): Boolean {
        val x = ev.rawX
        val y = ev.rawY
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                isMove = false
                isPress = true
                lastX = x
                lastY = y
                offsetX = getX() - x
                offsetY = getY() - y
            }
            MotionEvent.ACTION_MOVE -> {
                isMove = isMove(ev)
                isPress = if (isMove) {
                    if (!isChangeBg) {
                        isChangeBg = true
                        //思路:這里換背景圖
                    }
                    val xandY = getXandY(x + offsetX, y + offsetY)
                    setX(xandY[0].toFloat())
                    setY(xandY[1].toFloat())
                    false
                } else {
                    true
                }
            }
            MotionEvent.ACTION_UP -> {
                isChangeBg = false
                if (isPress) {
                    callback?.click()
                    isPress = true
                }
                if (isMove) {
                    isMove = false
                }
                if (x != 0f || x != (mScreenWith - mWidth).toFloat()) {
                    if (x <= halfWith) {
                        //在左半邊,吸附左邊
                        if (x >lastX) {
                            animate().setInterpolator(DecelerateInterpolator())
                                .setDuration(500)
                                .xBy(-x - offsetX)
                                .start()
                                //思路:這里換背景圖
                        }
                    } else {
                        //在右半邊,吸附右邊
                        if (x < laxtX) {
                            animate().setInterpolator(DecelerateInterpolator())
                                .setDuration(500)
                                .xBy(mScreenWith - mWidth - x - offsetX)
                                .start()
                               //思路:這里換背景圖
                        }
                    }
                }
            }
        }
        return true
    }

    /**
     * 獲取移動(dòng)到的x和y
     */
    private fun getXandY(x: Float, y: Float): IntArray {
        val resultX = when {
            x < 0 -> {
                0
                 //思路:這里換背景圖
            }
            x > mScreenWith - mWidth -> {
                mScreenWith - mWidth
                 //思路:這里換背景圖
            }
            else -> {
                x.toInt()
            }
        }
        val resultY: Int = when {
            y < mTop -> {
                mTop
            }
            y > mScreenHeight - mBottom - mWidth -> {
                mScreenHeight - mBottom - mWidth
            }
            else -> {
                y.toInt()
            }
        }
        return intArrayOf(resultX, resultY)
    }


    private var callback: OnClickCallback? = null

    fun setOnClickCallback(callback: OnClickCallback) {
        this.callback = callback
    }

    interface OnClickCallback {
        fun click()
    }

    private fun isMove(ev: MotionEvent): Boolean {
        val x = ev.rawX
        val y = ev.rawY
        val moreSpace =
            Math.sqrt(((x - lastX) * (x - lastX) + (y - lastY) * (y - lastY)).toDouble())
        return moreSpace > MORE_SPACE
    }
}

第二步.上布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="@dimen/dp_60"
    android:layout_height="@dimen/dp_60">

    <ImageView
        android:id="@+id/iv_playing_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/bg_playing" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/playing"
        android:layout_margin="@dimen/dp_5" />

</RelativeLayout>

第三步.使用

//設(shè)置可移動(dòng)范圍,正常是要貼邊手機(jī)兩側(cè),所以僅需要特別標(biāo)注上下邊距,畢竟不能滑動(dòng)到狀態(tài)欄和底部tab上去
floatView.setParentSize(手機(jī)寬,手機(jī)高,上邊距,下邊距)
//點(diǎn)擊事件嘛,處理點(diǎn)擊后的業(yè)務(wù)
floatView.setOnClickCallback(...)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末改衩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子坛增,更是在濱河造成了極大的恐慌搪柑,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件编振,死亡現(xiàn)場離奇詭異缀辩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)踪央,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門臀玄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人畅蹂,你說我怎么就攤上這事健无。” “怎么了液斜?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵累贤,是天一觀的道長。 經(jīng)常有香客問我旗唁,道長畦浓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任检疫,我火速辦了婚禮讶请,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屎媳。我一直安慰自己夺溢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布烛谊。 她就那樣靜靜地躺著风响,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丹禀。 梳的紋絲不亂的頭發(fā)上状勤,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音双泪,去河邊找鬼持搜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛焙矛,可吹牛的內(nèi)容都是我干的葫盼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼村斟,長吁一口氣:“原來是場噩夢啊……” “哼贫导!你這毒婦竟也來了抛猫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤孩灯,失蹤者是張志新(化名)和其女友劉穎闺金,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峰档,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掖看,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了面哥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毅待,死狀恐怖尚卫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尸红,我是刑警寧澤吱涉,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站外里,受9級(jí)特大地震影響怎爵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盅蝗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一鳖链、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧墩莫,春花似錦芙委、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至裂问,卻和暖如春侧啼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堪簿。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工痊乾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人戴甩。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓符喝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親甜孤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子协饲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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