使用Kotlin實(shí)現(xiàn)自定義LayoutManager+ItemTouchHelper實(shí)現(xiàn)炫酷卡片布局

使用Kotlin實(shí)現(xiàn)自定義LayoutManager+ItemTouchHelper實(shí)現(xiàn)炫酷卡片布局
很久沒有寫博客了,最近看到了一個(gè)比較好的卡片效果泻骤,自己就使用Kotlin來實(shí)現(xiàn)這個(gè)效果練練手

  • 效果如下:


    卡片效果
  • 分析:使用RecyclerView的自定義LayoutManager+ItemTouchHelper實(shí)現(xiàn)效果
  • 步驟:
  • 1、自定義LayoutManager珊肃,處理卡片的層疊顯示效果
  • 2纽什、使用ItemTouchHelper實(shí)現(xiàn)任何方向的拖動(dòng)效果,并在拖動(dòng)回調(diào)中處理數(shù)據(jù)

自定義LayoutManager只需要實(shí)現(xiàn)兩個(gè)方法:generateDefaultLayoutParams()和onLayoutChildren(),代碼中注釋寫的很清楚了与柑,下面就直接上代碼

  • generateDefaultLayoutParams()的套路基本一樣
override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT)
    }
  • onLayoutChildren()
 override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
        //將view放到RecyclerView的回收站中
        detachAndScrapAttachedViews(recycler)
        //設(shè)置開始遍歷的position
        var initPosition: Int

        if (CardConfig.MAX_SHOW_COUNT > itemCount) {
            initPosition = 0
        } else {
            initPosition = itemCount - CardConfig.MAX_SHOW_COUNT
        }

        //循環(huán)遍歷谤辜,擺放子view
        for (position in initPosition..itemCount - 1 ) {
            //獲取到回收站中的view
            val view = recycler!!.getViewForPosition(position)
            //將view添加到RecyclerView中
            addView(view)
            //測(cè)量view
            measureChild(view, 0, 0)
            //擺放控件(布局裝飾)
            var decorateWidth = getDecoratedMeasuredWidth(view)
            var decorateHeight = getDecoratedMeasuredHeight(view)
            var left=(width- decorateWidth)/2
            var top=(height- decorateHeight)/2
            layoutDecorated(view, left, top, left + decorateWidth, top + decorateHeight)
            //動(dòng)畫處理(移動(dòng),縮放)
            val level = itemCount - position - 1
            if (level > 0) {
                view.scaleX = 1f - CardConfig.SCALE_GAP * level
                view.scaleY = 1f - CardConfig.SCALE_GAP * level
                if (level < CardConfig.MAX_SHOW_COUNT-1) {
                    view.translationY = CardConfig.TRANS_Y_GAP * level.toFloat()
                }else{
                    view.translationY=CardConfig.TRANS_Y_GAP * (level - 1).toFloat()
                }
            }
        }
    }
  • 走到這里不出意外就能運(yùn)行出一下效果了
    卡片界面

    ItemTouchHelper.CallBack的關(guān)鍵代碼
  • 滑動(dòng)回調(diào)onSwiped()
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder?, direction: Int) {
        //交換item的位置价捧,并刷新適配器
        val user = mDatas.removeAt(viewHolder!!.layoutPosition)
        mDatas.add(0,user)
        mAdapter.notifyItemMoved(viewHolder!!.layoutPosition,0)
    }

走到這里應(yīng)該能看到以下效果

卡片動(dòng)效

其實(shí)走到這里離成功就很近了丑念,可以看出這里的動(dòng)畫效果比較生硬,所以下面再實(shí)現(xiàn)一個(gè)反向的動(dòng)畫即可

  • 實(shí)現(xiàn)反向動(dòng)畫结蟋,動(dòng)畫繪制子view,onChildDraw()
override fun onChildDraw(c: Canvas?, recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
        //給一個(gè)反向的過渡動(dòng)畫

        //這里模擬生成一個(gè)0-1的值
        val maxDistance = recyclerView!!.width * 0.5f
        val distance = Math.sqrt(dX * dX + dY * dY.toDouble())
        var fraction:Double = distance / maxDistance.toDouble()
        if (fraction > 1) {
            fraction = 1.0
        }

        val itemCount = recyclerView.childCount
        for (i in 0..itemCount - 1) {
            val view = recyclerView.getChildAt(i)
            val level = itemCount - i - 1

            if (level >= 0) {
                if (level < CardConfig.MAX_SHOW_COUNT - 1) {
                    //當(dāng)level是0到MAX_SHOW_COUNT-2
                    view.translationY = (CardConfig.TRANS_Y_GAP * level - fraction * CardConfig.TRANS_Y_GAP).toFloat()
                    view.scaleX = (1 - CardConfig.SCALE_GAP * level + fraction * CardConfig.SCALE_GAP).toFloat()
                    view.scaleY = (1 - CardConfig.SCALE_GAP * level + fraction * CardConfig.SCALE_GAP).toFloat()
                } else if (level == CardConfig.MAX_SHOW_COUNT - 1) {
                    // level是MAX_SHOW_COUNT-1
                    view.translationY = CardConfig.TRANS_Y_GAP * (level - 1).toFloat()
                    view.scaleX = 1 - CardConfig.SCALE_GAP * (level - 1).toFloat()
                    view.scaleY = 1 - CardConfig.SCALE_GAP * (level - 1).toFloat()
                }
            }
        }

        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
    }

好了脯倚,基本完工了,具體代碼移步github(喜歡就star一下哦):SwipeCardLayoutManagerDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末椎眯,一起剝皮案震驚了整個(gè)濱河市挠将,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌编整,老刑警劉巖舔稀,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異掌测,居然都是意外死亡内贮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門汞斧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夜郁,“玉大人,你說我怎么就攤上這事粘勒【憾耍” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵庙睡,是天一觀的道長(zhǎng)事富。 經(jīng)常有香客問我技俐,道長(zhǎng),這世上最難降的妖魔是什么统台? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任雕擂,我火速辦了婚禮,結(jié)果婚禮上贱勃,老公的妹妹穿的比我還像新娘井赌。我一直安慰自己,他們只是感情好贵扰,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布仇穗。 她就那樣靜靜地躺著,像睡著了一般拔鹰。 火紅的嫁衣襯著肌膚如雪仪缸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天列肢,我揣著相機(jī)與錄音恰画,去河邊找鬼。 笑死瓷马,一個(gè)胖子當(dāng)著我的面吹牛拴还,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播欧聘,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼片林,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了怀骤?” 一聲冷哼從身側(cè)響起费封,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒋伦,沒想到半個(gè)月后弓摘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痕届,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年韧献,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片研叫。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锤窑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嚷炉,到底是詐尸還是另有隱情渊啰,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布申屹,位于F島的核電站虽抄,受9級(jí)特大地震影響走搁,放射性物質(zhì)發(fā)生泄漏独柑。R本人自食惡果不足惜迈窟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忌栅。 院中可真熱鬧车酣,春花似錦、人聲如沸索绪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瑞驱。三九已至娘摔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唤反,已是汗流浹背凳寺。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留彤侍,地道東北人肠缨。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像盏阶,于是被迫代替她去往敵國(guó)和親晒奕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,303評(píng)論 25 707
  • 堅(jiān)持本身就是一種才華,畢竟你的努力擺在那里砰盐,這是任誰也泯滅不了的闷袒。 -1- 我發(fā)現(xiàn)最近朋友圈賣貨的消停了不少,那些...
    子豪同學(xué)c閱讀 348評(píng)論 0 0
  • 一周總結(jié) 1.快樂痛苦四原則: 好消息分開說楞卡,增加好消息帶給個(gè)人的滿足感霜运。壞消息一起說,減小對(duì)方的痛感蒋腮。一個(gè)大好消...
    自如得己閱讀 221評(píng)論 0 0
  • 今天下著小雨淘捡,還是坐著大潤(rùn)發(fā)班車去了市里去照相,結(jié)果去的早沒開門池摧,去了超市逛了逛焦除,之后打電話知道九點(diǎn)開門又去照的...
    閑敲棋子落燈花兒閱讀 166評(píng)論 0 0