java displaymenu_MenuDisplayView -- 一个带轮播功能的菜单

本文介绍如何自定义一个名为MenuDisplayView的ViewGroup,实现类似ViewPager的菜单轮播效果。通过分析需求,创建两种布局模式:展开(ListView)和收起(轮播ViewPager)。在onMeasure和onLayout方法中,根据不同模式计算尺寸和布局子视图。此外,还实现了动画效果,包括展开和收起的过渡动画。文章提供了详细的代码解析和动画实现过程。
摘要由CSDN通过智能技术生成

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

好久没有写过文章了,借着前几天 UI 提出的一个“简单”的动画需求,写写自己实现的

原本想着改改动画就算了,结果写完之后发现把自定义 ViewGroup 该用的知识差不多都涉及到了,那么就写篇文章来一起复习一下自定义一个 ViewGroup 的流程。接下来看看我们要实现的效果,咱们就开始进入正题了。

7ef4187d1efd

MenuDisplayView.gif

简单的分析

需求里的 menu item 其实没有像 demo 上显示的那样——都是同样类型的,事实上有直接添加在 xml 布局里面的,也有从接口请求下来之后再添加进去的。所以需要定义一个 ViewGroup,不管子 View 是啥样子的往里面添加就是。

ViewGroup 需要两种不同的布局方式:一种是展开时候的,看上去和 LinearLayout 一致;另一种是收起时候的,看上去像我们常用的 ViewPager 轮播一样。根据两种不同的模式,需要实现两种不同的测量和布局方式。

收起和展开按钮需要在 EggacheDisplayView 构造的时候动态添加进去。

简单的准备

在讲具体的 onMeasure 和 onLayout 方法之前,需要简单的看下构造方法。

public EggacheDisplayView(@NonNull Context context, @Nullable AttributeSet attrs,

int defStyleAttr) {

super(context, attrs, defStyleAttr);

TypedArray typedArray = context.obtainStyledAttributes(

attrs, R.styleable.EggacheDisplayView, 0, 0);

mBtnSpacing = typedArray.getDimensionPixelSize(

R.styleable.EggacheDisplayView_btn_spacing, dpToPx(context, 10));

int layoutCollapse = typedArray.getResourceId(

R.styleable.EggacheDisplayView_collapse_layout,

R.layout.layout_collapse_button);

int layoutExpand = typedArray.getResourceId(

R.styleable.EggacheDisplayView_expand_layout, R.layout.layout_expand_button);

mClickLoopToExpand = typedArray.getBoolean(

R.styleable.EggacheDisplayView_click_loop_to_expand, false);

typedArray.recycle();

createCollapseAndExpandButton(context, layoutCollapse, layoutExpand);

}

这里只有简单的几个自定义属性,mBtnSpacing 是每个子 view 之间的间隔,后面测量和布局的时候会用到,至于两个 layout 则分别是我们 createCollapseAndExpandButton 方法要添加进去的两个按钮。

另外定义了一个枚举类,表示是在展开状态还是在轮播状态。

public enum DisplayMode {

LIST,

LOOP

}

onMeasure 方法

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = 0;

int height = 0;

mMaxButtonWidth = 0;

mMaxButtonHeight = 0;

// 1.

for (int i = 0; i < getChildCount(); i++) {

View child = getChildAt(i);

if (child.getVisibility() == GONE) continue;

measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);

mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());

mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight());

}

// 2.

if (mDisplayMode == DisplayMode.LIST) {

// DisplayMode.LIST 相当于 LinearLayout

for (int i = 0; i < getChildCount(); i++) {

View child = getChildAt(i);

if (child.getVisibility() == GONE) continue;

height += child.getMeasuredHeight();

// 最后一个

if (i != getChildCount() - 1) {

height += mBtnSpacing;

}

}

} else if (mDisplayMode == DisplayMode.LOOP) {

// DisplayMode.LOOP 高度只包括 最高的子 view 的高度 + mBtnExpand 的高度

height += mMaxButtonHeight + mBtnSpacing + mBtnExpand.getMeasuredHeight();

}

width = mMaxButtonWidth + getPaddingLeft() + getPaddingRight();

height += getPaddingTop() + getPaddingBottom();

// 3.

if (getLayoutParams().width == LayoutParams.MATCH_PARENT) {

width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

}

if (getLayoutParams().height == LayoutParams.MATCH_PARENT) {

height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);

}

setMeasuredDimension(width, height);

}

从之前的分析来看,其实不适合继承 Lin

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值