资讯详情

资讯详情

MaterialDrawer 自定义 DrawerItem 完全指南:从实现接口到定制视图绑定

移动开发UI组件【免费下载链接】MaterialDrawerThe flexible, easy to use, all in one drawer library for your Android project. Now brand new with material 2 design.项目地址https://gitcode.com/gh_mirrors/ma/MaterialDrawer点击查看免费下载本指南围绕 MaterialDrawer 的核心扩展机制展开如何在现有抽屉中修改内置 DrawerItem 的外观行为或从零实现属于自己的 CustomDrawerItem。文中将以官方示例应用app模块中drawerItems包下的多套真实实现为骨架如 CustomPrimaryDrawerItem.kt、CustomUrlPrimaryDrawerItem.kt并对照库内IDrawerItem接口与AbstractDrawerItem抽象类的底层实现逐层拆解。读完你将掌握三种自定义路径扩展内置类、扩展抽象基类、直接实现接口、layoutRes/type/bindView三个关键契约的用法以及如何在MaterialDrawerSliderView.itemAdapter中接入这些自定义条目。一、先理解 DrawerItem 的架构一切自定义的起点在动手写自定义 Item 之前需要先弄清 MaterialDrawer 中 DrawerItem 的基本契约。抽屉内的每一项都实现自同一个接口 IDrawerItem.ktinterface IDrawerItemVH : RecyclerView.ViewHolder : IItemVH, IItemVHFactoryVH, IItemViewGenerator, IExpandableVH, IIdentifyable, Selectable, Tagable { override val type: Int // 唯一类型标识用于 RecyclerView 复用 val layoutRes: Int // 条目使用的布局资源 override var identifier: Long override fun generateView(ctx: Context): View override fun getViewHolder(parent: ViewGroup): VH override fun bindView(holder: VH, payloads: ListAny) ... }对于自定义而言真正需要关心的只有三个要素要素作用说明layoutRes决定条目渲染成什么样子返回一个布局文件资源 ID如库内默认的material_drawer_item_primarytype决定 RecyclerView 如何复用 ViewHolder每个自定义 Item 应返回全局唯一的资源 ID避免与其他条目共享 ViewHolder 导致视图状态串扰bindView(holder, payloads)把模型数据绑定到视图是自定义逻辑的核心入口几乎所有定制都在这里发生库内为开发者铺好了层层递进的继承链对应 AbstractDrawerItem.kt、BaseDrawerItem.kt、BaseDescribeableDrawerItem.kt、AbstractBadgeableDrawerItem.ktIDrawerItem └─ AbstractDrawerItemT, VH // 通用能力identifier、tag、isEnabled、isSelected、isSelectable、typeface、subItems…… └─ BaseDrawerItemT, VH // 基础属性icon、iconColor、selectedIcon、name、textColor、isIconTinted、level └─ BaseDescribeableDrawerItemT, VH // 增加 description、descriptionTextColor内置 bindViewHelper() └─ AbstractBadgeableDrawerItemT // 增加 badge、badgeStyle └─ PrimaryDrawerItem // 开箱即用的主条目同时库内提供了默认 ViewHolder —— BaseViewHolder.kt它按惯例绑定三个控件 IDmaterial_drawer_icon、material_drawer_name、material_drawer_description。自定义条目如果复用标准布局也可以直接复用这个 ViewHolder。二、自定义 DrawerItem 的三条路径从示例应用app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/下的实现看官方提供了三种自定义策略可按需求强度选择扩展内置具体类最轻量如CustomCenteredPrimaryDrawerItem、GmailDrawerItem只需覆盖layoutRes/type或主题方法扩展抽象基类中等如CustomPrimaryDrawerItem可新增属性并覆写bindView直接继承AbstractDrawerItem/BaseDrawerItem自建体系最彻底如CustomUrlBasePrimaryDrawerItem、IconDrawerItem、OverflowMenuDrawerItem完全掌控布局与绑定逻辑。三、路径一扩展内置类只改布局或主题3.1 换布局CustomCenteredPrimaryDrawerItem如果只是想换一套布局、沿用原有全部行为直接继承PrimaryDrawerItem并覆写两个属性即可。示例 CustomCenteredPrimaryDrawerItem.ktclass CustomCenteredPrimaryDrawerItem : PrimaryDrawerItem() { override val layoutRes: Int get() R.layout.material_drawer_item_primary_centered override val type: Int get() R.id.material_drawer_item_centered_primary }配套布局 material_drawer_item_primary_centered.xml 是一个水平LinearLayout图标、名称、描述、badge 全部居中android:gravitycenter且复用了库内的标准控件 IDmaterial_drawer_icon、material_drawer_name、material_drawer_description、material_drawer_badge。这正是关键点——只要布局里保留这些 ID就能无缝继承父类的bindView逻辑。两个注意点type必须唯一这里使用在 app/src/main/res/values/ids.xml 中预定义的material_drawer_item_centered_primary自定义type时建议在 app 模块的ids.xml里声明一个专用资源 ID示例中gmail_item、custom_url_item、icon_only、overflow_menu、profile_item_divider均如此定义而不是复用现有 ID否则会被当作同一种条目复用同一个 ViewHolder。3.2 改主题与形状GmailDrawerItem如果目标是改变选中态背景、圆角等主题表现可以覆写applyDrawerItemTheme与getShapeAppearanceModel。示例 GmailDrawerItem.kt 模拟了 Gmail 风格——仅右侧圆角的选中高亮open class GmailDrawerItem : PrimaryDrawerItem() { override val type: Int get() R.id.material_drawer_item_gmail_item override fun applyDrawerItemTheme(ctx: Context, view: View, selected_color: Int, animate: Boolean, shapeAppearanceModel: ShapeAppearanceModel) { themeDrawerItem(ctx, view, selected_color, animate, shapeAppearanceModel, R.dimen.gmail_material_drawer_item_background_padding_top_bottom, R.dimen.gmail_material_drawer_item_background_padding_start, R.dimen.gmail_material_drawer_item_background_padding_end, isSelected isSelected) } override fun getShapeAppearanceModel(ctx: Context): ShapeAppearanceModel { val cornerRadius ctx.resources.getDimensionPixelSize(R.dimen.gmail_material_drawer_item_corner_radius) return ShapeAppearanceModel.builder() .setTopRightCorner(CornerFamily.ROUNDED, cornerRadius.toFloat()) .setBottomRightCorner(CornerFamily.ROUNDED, cornerRadius.toFloat()) .build() } }底层由themeDrawerItem支撑DrawerUtils.kt它基于ShapeAppearanceModel构建MaterialShapeDrawable作为选中态背景外层套InsetDrawable控制选中高亮的内边距未选中态在 API 21 使用RippleDrawablecolorControlHighlight作为按压色低版本则退化为StateListDrawable并可借animate参数控制状态切换的淡入淡出。覆写这两个方法即可自定义选中圆角、内边距与按压反馈。四、路径二扩展抽象基类新增属性并覆写 bindView4.1 加背景色CustomPrimaryDrawerItemCustomPrimaryDrawerItem继承自AbstractBadgeableDrawerItem因此天然拥有 badge 能力它只新增了一个background属性CustomPrimaryDrawerItem.ktclass CustomPrimaryDrawerItem : AbstractBadgeableDrawerItemCustomPrimaryDrawerItem() { var background: ColorHolder? null fun withBackgroundColor(backgroundColor: Int): CustomPrimaryDrawerItem { this.background ColorHolder.fromColor(backgroundColor) return this } fun withBackgroundRes(backgroundRes: Int): CustomPrimaryDrawerItem { this.background ColorHolder.fromColorRes(backgroundRes) return this } override fun bindView(holder: AbstractBadgeableDrawerItem.ViewHolder, payloads: ListAny) { super.bindView(holder, payloads) background?.applyToBackground(holder.itemView) } }这里的模式值得记住属性与with方法并存var background: ColorHolder?是 Kotlin 属性同时提供withBackgroundColor(Int)/withBackgroundRes(Int)两个流式方法兼容 Java 调用与链式写法ColorHolder延迟解析ColorHolder.kt 同时保存colorInt与colorRes在真正应用时才解析为具体颜色不需要提前持有ContextapplyToBackground(view)在colorInt非 0 时调用view.setBackgroundColor(...)否则按colorRes走setBackgroundResource(...)先super.bindView再追加父类已完成名称、描述、图标、badge、选中态背景等全部标准绑定子类只需做增量修改。4.2 使用时如何配置在 AdvancedActivity.kt 中它被配置为带强调色背景的条目CustomPrimaryDrawerItem().apply { nameRes R.string.drawer_item_free_play iconicsIcon FontAwesome.Icon.faw_gamepad background ColorHolder.fromColorRes(R.color.colorAccent) }注意这里直接对公开属性赋值background ...而不是调用withBackgroundRes两种方式等价——这正是新版 API 从withXxx方法向 Kotlin 属性迁移的体现IDrawerItem中仍保留了少量withIdentifier等Deprecated扩展见 IDrawerItem.kt。五、路径三自建体系——从 BaseDrawerItem 起步的完整实现当内置类的形态无法满足需求时例如条目需要 URL 图标 描述 badge 的组合可以直接继承BaseDrawerItem或AbstractDrawerItem。示例应用用CustomUrlBasePrimaryDrawerItemCustomUrlPrimaryDrawerItem展示了完整的抽象基类 具体实现分层写法。5.1 抽象基类承载通用绑定逻辑CustomUrlBasePrimaryDrawerItem.kt 继承BaseDrawerItemT, VH()注意这里的泛型约束VH : RecyclerView.ViewHolder即不强制绑定库内BaseViewHolder新增description与descriptionTextColor属性并提供了一个受保护的bindViewHelper(viewHolder: CustomBaseViewHolder)复用方法。其核心绑定步骤依次为viewHolder.itemView.id hashCode()把 item 的 hash 写入视图 ID便于测试与定位通过getSelectedColor(ctx)/getColor(ctx)解析选中色与文本色调用themeDrawerItem(...)设置带圆角与内边距的选中态背景StringHolder.applyTo(name, viewHolder.name)绑定名称StringHolder.applyToOrHide(description, viewHolder.description)绑定描述为空则隐藏设置文本颜色与 typeface先DrawerImageLoader.instance.cancelImage(viewHolder.icon)并清空 bitmap再icon?.applyTo(viewHolder.icon, customUrlItem)加载图标调用setDrawerVerticalPadding(view)修正 API 17 以下的 padding 兼容问题详见 Extensions.kt最后设置选中态。该基类同时提供了两个图标入口fun withIcon(url: String): T { this.icon ImageHolder(url) return this as T } fun withIcon(uri: Uri): T { this.icon ImageHolder(uri) return this as T }ImageHolderImageHolder.kt支持 URL、Uri、Drawable、Bitmap、资源 ID 五种来源解析时机同样被推迟到应用时。其中 URL 加载走 DrawerImageLoader.kt 单例——默认只处理http/https协议handledProtocols并可注入任意图片加载库实现IDrawerImageLoader接口若协议未被接管则回退到imageView.setImageURI(uri)。5.2 具体实现绑定 badge 并产出专用 ViewHolderCustomUrlPrimaryDrawerItem.kt 继承该基类并实现ColorfulBadgeable接口class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItemCustomUrlPrimaryDrawerItem, CustomUrlPrimaryDrawerItem.ViewHolder(), ColorfulBadgeable { override var badge: StringHolder? null override var badgeStyle: BadgeStyle? BadgeStyle() override val type: Int get() R.id.material_drawer_item_custom_url_item override val layoutRes: Int get() com.mikepenz.materialdrawer.R.layout.material_drawer_item_primary override fun bindView(holder: ViewHolder, payloads: ListAny) { super.bindView(holder, payloads) bindViewHelper(holder) // 复用基类的通用绑定 val badgeVisible StringHolder.applyToOrHide(badge, holder.badge) if (badgeVisible) { badgeStyle!!.style(holder.badge, getColor(ctx)) holder.badge.visibility View.VISIBLE } else { holder.badge.visibility View.GONE } if (typeface ! null) { holder.badge.typeface typeface } onPostBindView(this, holder.itemView) // 触发外部后置绑定监听器 } override fun getViewHolder(v: View): ViewHolder ViewHolder(v) class ViewHolder(view: View) : CustomBaseViewHolder(view) { internal val badge: TextView view.findViewById(R.id.material_drawer_badge) } }三个要点layoutRes直接复用库内布局com.mikepenz.materialdrawer.R.layout.material_drawer_item_primary见 material_drawer_item_primary.xml因此ViewHolder只需在基类基础上补一个badge引用type使用自定义 IDmaterial_drawer_item_custom_url_item与标准主条目区分开避免 ViewHolder 复用冲突onPostBindView钩子AbstractDrawerItem会在绑定末尾回调onPostBindViewListenerAbstractDrawerItem.kt允许不创建子类、仅通过监听器对已绑定视图做后置修改。在 AdvancedActivity.kt 中的典型用法是传入头像 URL 与描述CustomUrlPrimaryDrawerItem().apply { nameRes R.string.drawer_item_fragment_drawer description StringHolder(R.string.drawer_item_fragment_drawer_desc) iconUrl https://avatars3.githubusercontent.com/u/1476232?v3s460 }StringHolderStringHolder.kt同样支持字符串与资源两种形态applyToOrHide会在文本为空时自动隐藏对应 TextView。六、两个更极端的自定义范例6.1 纯图标条目IconDrawerItemIconDrawerItem.kt 直接继承AbstractDrawerItem并实现Iconable、SelectIconable使用仅含一个 ImageView 的布局 material_drawer_item_icon_only.xmloverride val type: Int get() R.id.material_drawer_item_icon_only override val layoutRes: Int get() R.layout.material_drawer_item_icon_only override fun bindView(holder: ViewHolder, payloads: ListAny) { super.bindView(holder, payloads) val iconColor this.iconColor ?: ctx.getPrimaryDrawerIconColor() val icon ImageHolder.decideIcon(icon, ctx, iconColor, isIconTinted, 1) val selectedIcon ImageHolder.decideIcon(selectedIcon, ctx, iconColor, isIconTinted, 1) ImageHolder.applyMultiIconTo(icon, selectedIcon, iconColor, isIconTinted, holder.icon) onPostBindView(this, holder.itemView) }注意它复用了BaseViewHolder中material_drawer_icon的 ID 约定但bindView完全自行实现——不调用任何bindViewHelper说明自定义 Item 的绑定逻辑可以全部自己说了算。ImageHolder.applyMultiIconTo会根据是否设置了selectedIcon与isIconTinted决定生成StateListDrawable还是直接设置普通图标。6.2 带溢出菜单的条目OverflowMenuDrawerItemOverflowMenuDrawerItem.kt 继承BaseDescribeableDrawerItem拥有bindViewHelper复用在布局 material_drawer_item_overflow_menu_primary.xml 的右侧加入了一个ImageButtonIDmaterial_drawer_menu_overflow。它在bindView中完成菜单点击事件的装配holder.menu.setOnClickListener { view - val popup PopupMenu(view.context, view) val inflater popup.menuInflater inflater.inflate(menu, popup.menu) popup.setOnMenuItemClickListener(onMenuItemClickListener) popup.setOnDismissListener(onDismissListener) popup.show() } holder.menu.setImageDrawable(IconicsDrawable(ctx, GoogleMaterial.Icon.gmd_more_vert) .apply { sizeDp 12; colorList getIconColor(ctx) })使用示例见 AdvancedActivity.kt通过menu、onMenuItemClickListener属性注入菜单资源与回调图标则使用 Iconics 图标库gmd_filter_center_focus。七、把自定义 Item 接入抽屉自定义条目本身也是IDrawerItem因此与内置条目用法完全一致通过MaterialDrawerSliderView.itemAdapter.add(...)加入列表即可。MaterialDrawerSliderView.kt 中itemAdapter是ItemAdapterIDrawerItem*并与headerAdapter、secondaryItemAdapter、footerAdapter一起被组装进FastAdapter共同支撑抽屉的 RecyclerView。AdvancedActivity.kt 展示了完整混用内置PrimaryDrawerItem、自定义OverflowMenuDrawerItem、CustomPrimaryDrawerItem、CustomUrlPrimaryDrawerItem、SectionDrawerItem、SecondaryDrawerItem按顺序加入同一个列表并配合addStickyDrawerItems(...)添加底部固定项。当多个自定义类型同时出现时type的唯一性保证各自 ViewHolder 互不干扰。八、编写自定义 DrawerItem 的检查清单综合示例应用的实现与库源码落地一个自定义 DrawerItem 时建议依次确认继承层级优先考虑扩展PrimaryDrawerItem/SecondaryDrawerItem等内置类需要 badge 则用AbstractBadgeableDrawerItem需要完全定制才下沉到BaseDrawerItem/AbstractDrawerItem布局与 ID 契约自定义layoutRes时若想复用父类绑定逻辑务必保留material_drawer_icon、material_drawer_name、material_drawer_description以及 badge 场景的material_drawer_badge等标准 IDtype 唯一性在ids.xml中为每个自定义类型声明独立 ID切勿与库内 ID 冲突bindView 的调用顺序先super.bindView(holder, payloads)再叠加自定义逻辑若要复用标准样式与图标加载调用bindViewHelper(holder)最后可调用onPostBindView(this, holder.itemView)触发外部监听器数据源封装颜色用ColorHolder、文本用StringHolder、图片用ImageHolder三者均支持资源 ID / 原始值双形态并在应用时延迟解析还能在无值时自动隐藏对应控件可配置性为新增属性提供withXxx链式方法或直接暴露 Kotlin 属性保持与库内 API 风格一致。至此从接口契约到 ViewHolder 绑定、从换布局到自定义主题、从加属性到自建体系MaterialDrawer 自定义 DrawerItem 的完整链路已经打通。需要进一步研究时可以继续阅读 FAQ、MIGRATION.md 以及库内 model 包 与 util 包 的其余实现。赞分享移动开发UI组件【免费下载链接】MaterialDrawerThe flexible, easy to use, all in one drawer library for your Android project. Now brand new with material 2 design.项目地址https://gitcode.com/gh_mirrors/ma/MaterialDrawer点击查看免费下载相关推荐Guice绑定机制完全指南从基础到高级自定义绑定Guice绑定机制完全指南从基础到高级自定义绑定 Guice是Google开发的轻量级依赖注入框架为Java开发者提供了强大而灵活的绑定机制。通过Guice后端Cocos Creator 引擎 SWIG 绑定工作流完全指南从自定义 C 模块到 JS 接口绑定Cocos Creator 引擎 SWIG 绑定工作流完全指南从自定义 C 模块到 JS 接口绑定 本指南以 Cocos Creator 引擎的 SWIG游戏开发图形学3D渲染SmartRefreshLayout 自定义 Header 和 Footer 完全指南从接口原理到实战实现SmartRefreshLayout 自定义 Header 和 Footer 完全指南从接口原理到实战实现 本篇技术指南聚焦 SmartRefreshLayo移动开发UI组件上一篇InsForge REST API参考所有端点详细说明下一篇Rerun ChannelId 组件详解MCAP 通道 16 位标识符在 Rerun 数据模型中的实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →