背景
我在项目中不止一次的要求写下拉菜单以选择参数,之前写的很乱,难以复用,写过单个菜单的,下次项目又要求两个menu,而且都要带translate动画效果。所以这次整理出一个自定义View(其实是个自定义RelativeLayout)。
效果
功能并不复杂,支持一或多个ListView与本控件绑定,支持自定义title,供有需之人取之。不多说,贴图:
代码分析
思路
本控件继承自RelativeLayout,考虑到展开时的黑色背景要铺开,所以width和height均默认MATCH_PARENT。并没有做太复杂的layout和draw,只是放置对应N个TextView&箭头drawable于顶部,以LinearLayout为container,组织成默认1:1的样式。这就要求控件在使用前提供几个必须的参数:listView的个数,相应的listView,以及相应的title。因此,在xml方式使用时,应提供足够的自定义参数。具体使用方式见使用指南。
核心是如何实现translate动画。如果使用ViewAnimation,画面上看起来移动但点击区域并没有位移。其实只要将listView实际位置设在title下方,动画开始就从-Y移动到0,点击时就没有问题。只不过我觉得既然3.0后属性动画已经引入,不如用性能更好的。所以该控件使用借助Scroller计算位移、通过对ListView设置translationY的方式完成位移效果。这样由于Scroller默认使用Viscous-Interpolator,效果也比匀速动画更官方范和美观。
还需要注意的是,该控件大致分为三个部分:Title,ListView以及黑色背景。这三者在addView的时候需要注意先后顺序,保证从顶至底为:Title-ListView-黑色背景。简易流程
如下,由postDelay来实现循环判断:
其中startScroll负责初始化参数:
if (mDirection == MOVE_DOWN) {
mScroller.startScroll(0, -mHeight, 0, mHeight, mDuration);
} else if (mDirection == MOVE_UP) {
mScroller.startScroll(0, 0, 0, -mHeight, mDuration);
}
附Github地址:源码
使用指南
From xml
<com.opticalix.dropdown_lib.DropdownView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/dropdown_view" android:layout_width="match_parent" android:layout_height="match_parent" app:drop_down_arrow_up="@mipmap/ic_arrow_up" app:drop_down_arrow_down="@mipmap/ic_arrow_down" app:drop_down_duration="200" app:drop_down_enable_dim="true" app:drop_down_list_count="2" app:drop_down_list_height="150dp" app:drop_down_title_background="@android:color/white" app:drop_down_title_drawable_padding="10dp" app:drop_down_title_padding_bottom="7dp" app:drop_down_title_padding_top="7dp" app:drop_down_title_text="@array/drop_down_titles" app:drop_down_title_text_color="#444444" app:drop_down_title_text_size="10sp"/>
然后关联对应的ListView,通常还需要设置item的点击回调事件。
mDropdownView = (DropdownView) findViewById(R.id.dropdown_view);
mDropdownView.setup(simpleListView1, simpleListView2);
mDropdownView.setOnDropdownItemClickListener(new DropdownView.OnDropdownItemClickListener() {
@Override
public void onItemClick(View v, int whichList, int position) {
mDropdownView.setTitleText(whichList, whichList + "-" + position);
}
});
- From code
新建该控件,调用setup初始化必要参数。
DropdownView dropdownView = new DropdownView(this);
dropdownView.setup(3, titles_arr, simpleListView1, simpleListView2, simpleListView3);
//config dropdownView...
//remember to addView
root.addView(dropdownView);
- 注意
在5.0以上手机有可能出现其他View覆盖本控件的现象,虽然明明是DropdownView最后添加,按理说应该处于最顶层…可能是引入MD风格后,Z轴方向加强管理而导致的覆盖机制变化。可通过setZ解决:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mDropdownView.setZ(100);//larger than others
}