资讯动态

Plaid自定义控件教程:打造拖拽弹性关闭的FrameLayout,5步掌握实现套路

发布时间:2026/9/19 20:07:53 来源:尧图企业网站定制
Plaid自定义控件教程打造拖拽弹性关闭的FrameLayout5步掌握实现套路【免费下载链接】plaidAn Android app which provides design news inspiration as well as being an example of implementing material design.项目地址: https://gitcode.com/gh_mirrors/pl/plaidPlaid 是一款经典的 Android 设计资讯应用也是 Material Design 实践的标杆项目。其中ElasticDragDismissFrameLayout是一个拖拽弹性关闭自定义控件页面跟着手指走、越拉越费劲弹性阻尼拉过阈值就自动关闭页面没拉够则平滑回弹。本文将它拆解为 5 个步骤帮你掌握这类自定义控件的完整实现套路 第 1 步理解原理——嵌套滚动如何驱动弹性拖拽很多新手做下拉关闭页面时会直接拦截触摸事件结果和内部列表的滚动冲突体验很糟。Plaid 的方案更优雅不抢手势而是监听嵌套滚动Nested Scroll中没被消费掉的偏移量。核心逻辑在 ElasticDragDismissFrameLayout.javaonStartNestedScroll()只声明对垂直方向的嵌套滚动感兴趣onNestedScroll()子列表滚到头后剩余的dyUnconsumed才交给父布局做拖拽位移onNestedPreScroll()处理用户中途反向回拉的手势避免状态混乱。 套路总结凡是包裹可滚动内容、要做二次手势的控件优先用 NestedScroll 接口而不是onInterceptTouchEvent抢事件。️ 第 2 步在 XML 中声明控件并配置 4 个属性控件继承自FrameLayout所以用法就是套一层壳。Plaid 在 Dribbble 作品详情页用它包裹整个内容区见 activity_dribbble_shot.xmlio.plaidapp.core.ui.widget.ElasticDragDismissFrameLayout android:idid/draggable_frame android:layout_widthmatch_parent android:layout_heightmatch_parent app:dragDismissDistancedimen/drag_dismiss_distance app:dragDismissScale0.95 !-- 你的页面内容比如 NestedScrollView -- /io.plaidapp.core.ui.widget.ElasticDragDismissFrameLayout四个可配置属性定义在 attrs_elastic_drag_dismiss_frame_layout.xml属性含义默认值dragDismissDistance触发关闭的拖拽距离像素无穷大dragDismissFraction按父布局高度百分比设定距离-1未启用dragDismissScale拖拽时的缩放终点比例0.95即缩到 95%1不缩放dragElasticity弹性系数位移放大/衰减倍数0.8Plaid 把距离设为 112dp正好是 2 倍 Action Bar 高度手感恰到好处——这个基于屏幕尺寸而非固定像素的取数思路值得学习。 第 3 步弹性公式与回弹动画核心数学橡皮筋手感的关键在 dragScale() 里的一个对数公式// 拖拽比例 0~1越接近阈值增长越慢 float dragFraction (float) Math.log10(1 (Math.abs(totalDrag) / dragDismissDistance));为什么用log10(1 x)拖拽初期位移≈真实手指位移跟手灵敏接近阈值后位移按对数递减怎么拉也拉不到头产生拉不动的橡皮筋阻力感。配合dragElasticity0.8衰减总位移再按需同步缩放shouldScale时把缩放轴心设为底部或顶部见 L205-L211视觉上就像页面从被拉出的那一端翘起。松手后的处理在 onStopNestedScroll()位移 ≥ 阈值 → 派发关闭回调否则 → 用 200ms 的fastOutSlowIn插值器动画回到原位这正是 Android 官方的快出慢进曲线回弹不生硬。 套路总结对数衰减做阻尼 系统级插值器做回弹两件套就是流畅弹性的全部秘密。 第 4 步回调监听与系统栏渐隐控件通过 ElasticDragDismissCallback 抽象类对外暴露两个回调onDrag(elasticOffset, elasticOffsetPixels, rawOffset, rawOffsetPixels)每帧拖拽都回调同时给出弹性后和原始两组偏移量方便你做渐变、缩放等联动效果onDragDismissed()确认关闭时触发。内置的 SystemChromeFader 是一个现成的演示向下拖时按rawOffset比例渐隐状态栏向上拖时渐隐底部导航栏关闭时调用finishAfterTransition()让转场动画自然衔接。子类化它即可定制自己的联动效果参考 ShotActivity.kt。⏱️ 第 5 步把监听器绑定到 Activity 生命周期最后一步是防内存泄漏的正确姿势Plaid 的做法ShotActivity.ktoverride fun onResume() { super.onResume() binding.draggableFrame.addListener(chromeFader) } override fun onPause() { binding.draggableFrame.removeListener(chromeFader) super.onPause() }只在页面可见时监听不可见即解绑——回调注册与视图生命周期对齐是自定义控件集成的通用规范。 五步套路小结步骤要点1️⃣ 原理用 NestedScroll 消费剩余滚动量不抢手势2️⃣ 声明FrameLayout 子类 declare-styleable自定义属性3️⃣ 弹性对数公式做阻尼 fastOutSlowIn 回弹动画4️⃣ 回调抽象 Callback 暴露 onDrag / onDragDismissed5️⃣ 生命周期onResume 注册、onPause 解绑这个控件在 Plaid 的设计新闻详情页、Dribbble 作品页和 About 页面均有应用源码集中在 core/src/main/java/io/plaidapp/core/ui/widget/ 目录。照着这 5 步你就能为自己的页面加上下拉关闭、下拉刷新之外的第三种手势体验 ✨【免费下载链接】plaidAn Android app which provides design news inspiration as well as being an example of implementing material design.项目地址: https://gitcode.com/gh_mirrors/pl/plaid创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价