自定义下拉菜单效果(仿美团等)

自定义下拉菜单效果(仿美团等),第1张

这是一个自定义布局容器实现的下拉菜单效果,看看实现该效果涉及到哪些东西,实现的一个大致流程和思路是啥样的;

通过上面的示意图大致分为:

对于下拉menu、menu显示的阴影遮罩、阴影遮罩下面的内容区域可以放到一个FrameLayout容器中,这样就可以把它看成是顶部tab、分割线、FrameLayout依次的上下摆放,在自定义布局容器时可以继承在LinearLayout设置垂直方向显示就ok了;

提供了下面这些自定义属性,在xml布局中可以通过其来设置显示效果;

根据上面的分析,自定义好布局容器后,在构造方法中先将tab容器、下滑分割线、FrameLayout容器创建好并添加到自定布局容器中;

创建并添加好后,就只剩下tab容器中显示的文字、分割线、menu、阴影遮罩、内容区域,而这些需要根据tab显示的数量来进行创建,通过setDropDownMenu方法来进行创建和设置,该方法需要出入一个tab显示的集合、menu对应的view集合、内容区域显示的view,根据传入的参数先来创建顶部tab;

tab中间分割线的创建需要根据mDividerShow的值来进行创建,内容区域比较简单,将传入的内容区域的view添加到初始化创建好的FrameLayout中就可以了;

接着添加遮罩层

一进入页面遮罩层以及后面的menu肯定是隐藏不可见的,

在创建menu设置其显示的高度时,根据对应的view来设置其显示的高度,如果是ListView或者GridView就会调用getTotalHeight()方法去计算所有item的高度如果大于当前屏幕的1/2就显示屏幕的1/2滑动滚动显示

如果是RecyclerView的话就调用setRecyclerViewHeight()方法,不过要在setDropDownMenu()方法之前调用,将获取到的所有item高度传入,

这时顶部tab、下滑分割线、menu、遮罩层、内容区域等就都创建并添加完毕了,剩下的就是点击顶部tab item时menu的显示、切换、点击menu时menu的隐藏等;在创建tab item时就已经给每个item添加了对应的点击事件了;

这里是根据mDividerShow的值也就是顶部tab 分割线是否显示来处理的,先看下有分割线的处理;

如果有中间分割线的话,在进行循环遍历是i的自增为2,menu通过getChildAt获取子view时就是i/2,如果没有显示中间分割线,遍历循环时就不用做这些处理,直接通过当前i就可以了;

通过currentTabPosition成员变量来判断打开、关闭、切换的逻辑,如果currentTabPosition为-1的,也就是回到了初始状态就是重新打开,将选中的menu、遮罩层显示出并添加一些动画效果,其他的则隐藏;如果currentTabPosition不为-1,并且和当前选中的i不相等代表的就是切换菜单 *** 作,遮罩层继续显示不用处理,将选中的menu显示,其他则隐藏;

如果currentTabPosition不为-1,且currentTabPosition和当前选中的i一致,就要将选中的menu进行关闭并隐藏遮罩层;

显示、切换、关闭menu就实现了,在布局文件中使用看下;

这样大致效果就实现了。

源码

Tab标签页是界面设计时经常使用的界面控件,可以实现多个分页之间的快速切换,每个分页可以显示不同的内容,下图是Android系统内置的Tab标签页,点击“呼出/接听键”后出现,用于电话呼出和查看拨号记录、联系人.

Tab标签页的使用

先要设计所有的分页的界面布局

在分页设计完成后,使用代码建立Tab标签页,并给每个分页添加标识和标题

最后确定每个分页所显示的界面布局

每个分页建立一个XML文件,用以编辑和保存分页的界面布局,使用的方法与设计普通用户界面没有什么区别

建立一个“TabDemo”程序,包含三个XML文件,分别为tab1.xml、tab2.xml和tab3.xml,这3个文件分别使用线性布局、相对布局和绝对布局示例中的main.xml的代码,并将布局的ID分别定义为layout01、layout02和layout03

关键代码如下:

10. public void onCreate(Bundle savedInstanceState) {

11. super.onCreate(savedInstanceState)

12. TabHost tabHost = getTabHost()

13. LayoutInflater.from(this).inflate(R.layout.tab1, tabHost.getTabContentView(),true)

14. LayoutInflater.from(this).inflate(R.layout.tab2, tabHost.getTabContentView(),true)

15. LayoutInflater.from(this).inflate(R.layout.tab3, tabHost.getTabContentView(),true)

16. tabHost.addTab(tabHost.newTabSpec("TAB1")

17. .setIndicator("线性布局").setContent(R.id.layout01))

18. tabHost.addTab(tabHost.newTabSpec("TAB2")

19. .setIndicator("绝对布局").setContent(R.id.layout02))

20. tabHost.addTab(tabHost.newTabSpec("TAB3")

21. .setIndicator("相对布局").setContent(R.id.layout03))

22.}

23. }

第8行代码的声明TabDemo类继承与TabActivity,与以往继承Activity不同,TabActivity支持内嵌多个Activity或View

第12行代码通过getTabHost()函数获得了Tab标签页的容器,用以承载可以点击的Tab标签和分页的界面布局。

第13行代码通过LayoutInflater将tab1.xml文件中的布局转换为Tab标签页可以使用的View对象

第16行代码使用addTab()函数添加了第1个分页,tabHost.newTabSpec("TAB1")表明在第12行代码中建立的tabHost上,添加一个标识为TAB1的Tab分页

第17行代码使用setIndicator()函数设定分页显示的标题,使用setContent()函数设定分页所关联的界面布局

在使用Tab标签页时,可以将不同分页的界面布局保存在不同的XML文件中,也可以将所有分页的布局保存在同一个XML文件中

第一种方法有利于在Eclipse开发环境中进行可视化设计,并且不同分页的界面布局在不同的文件中更加易于管理

第二种方法则可以产生较少的XML文件,同时编码时的代码也会更加简洁

一个Tab页,中间有个按钮可以跳转到另一个Activity

我的TabHost是

intent = new Intent(this,Activity01.class)//新建一个Intent用作Tab1显示的内容

spec = tabHost.newTabSpec("tab1")//新建一个 Tab

.setIndicator("tab1")//设置名称以及图标

.setContent(intent)//设置显示的intent,这里的参数也可以是R.id.xxx

tabHost.addTab(spec)//添加进tabHost

这个方式添加进来的,加载Acitivity01


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11777340.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-18
下一篇 2023-05-18

发表评论

登录后才能评论

评论列表(0条)

保存