Tab 模块 (二)

来源:互联网 发布:js比较两个数值大小 编辑:程序博客网 时间:2024/06/11 08:11
Tab 模块 (二)

一个TabMenu也是由一组View组成的,因此 extends了LinearLayout,
而为了模拟拖拽某个TabView到tabMenu外<但一直在代表屏幕的MovingMenu内>,和TabMenu同一级
<如果在TabMenu内,显然从TabMenu内拖不出来>的还有一个用于代表托拽时的TabView
的辅助性View.平常不可见,只有在托拽某个TabView时,才会截取TabView的内容到自己,然后显示在相应的托拽位置,并响应以后
操作.项目中经常用到类似这种处理托拽的辅助View的手法.

<1>TabMenu一定程度也是一个container,纯粹是为其他的部件提供容身之所,当然了,其实任何的ViewGroup都是这样。
TabMenu包含了真正显示TabView的List,以及相关的tab操作View.

<2>同样的是在onFinishInflate()初始化指向子View的引用以及配置相应的Listener.

<3>该层对TouchEvent都采用LinearLayout默认处理,下放若回来就回吐.

<4>该View承载起了监听相关M<Tab的变化信息,Tab增加,某个Tab被激活,Tab的Title变化等>变化的职责<可以认为是Facade模式>,
收到以后转交<调用>给子View处理.
同时也会监听上面的MovingMenu的一些event,通过implement其开放的Listener实现<而为了能够在这些回调中调用MovingMenu的
方法,TabMenu还需要维护一个到外部MovingMenu的引用>.
还有就是承载了一部分clickListener的逻辑,这可以视为是处理了一部分的TouchEvent<但是这部分TouchEvent其实是子View捕获处理的>.

<5>TabMenu适配portrait和landscape,
每次orentation发生变化的时候,都会将tabMenu直接隐藏<不带动画>,并且将orentation传递给子View,
为了实现UI的切换,会微调TabMenu和toolButton的padding/LayoutParam, 这里的修改padding和LayoutParam
都只是单纯的修改值,只有下一次layout时,才会有效果,因此,为了生效,会在后面调用一次requestLayout来
触发将新的setting反应到UI上。

<6>TabMeu对应的M是另外一个类TabManager<内部会有指向它的引用>,并且还有一个TabMenuInterface在规范其行为:
setAllowedExceedingTabCount(int count);
setSwooshView(FrameLayout swooshView);
setTabManager(TabManager tabManager);
setListener(Listener listener);
setPortraitMode(boolean portrait);
setAttachedToTop(boolean attachedToTop);
onStop();
onPause();
onResume();

<7>在调整View的layoutParams时,在通过getLayoutParams()得到以后,要做具体的类型转换,根据此
View所处的Layout决定<FrameLayout.LayoutParams/LinearLayout.LayoutParams>,然后就可以根据需求调整值,要生效必须有一次layout.
在设置WRAP_CONTENT这类参数时,还是使用ViewGroup,因为他们是在ViewGroup里定义的.

<8>ToolUI中的Button采用了TextView的setCompoundDrawables来实现显示图案+字符, 被设置的Drawable之前要调用setBound为其指定
好被draw的范围.

<9>虽然TabMenu作为View来说,本身有检测orentation变化的能力<onConfigurationChanged>,不过项目中为了统一控制,
基本都只由Activity做检测,然后Activity同意分发,因此TabMenu会有一个public的设置orentation的方法.

<10>对于onClickListner的实现:
对于点击到TabView和toolButton之外的click,都视为关闭Menu,直接调用前面保存的MovingMenu引用来执行Menu消失<这里可能用
Listener或者event更好,TabMenu最好不要知道MovingMenu的存在>
而对于点击了toolButton的click,则是添加一个新的Tab,这一步TabMenu要check是否允许再add Tab view, 如果add,
那么对于TabMenu类本身,不需要做什么<也确实不会影响到它>,而是通知Listener这次变化<这也是V的标准做法,用户操作了V,
V之应该这个event传递出去,最好不要自己替C/M代劳>.

<11>TabMenuInterface内部定义了一个接口用于开放对某些event的监听:
onTabClicked(Tab tab);
onAddTabClicked(Tab after);
onCloseTabClicked(Tab tab);
onCloseAllTabsClicked();
onShowTabMenu();
onHideTabMenu(TabMenuInterface menu);

<12>TabMenu除了实现父View开放的监听接口,还实现了内部子View类开放的监听接口,
整个通知event的流向不再是单一方向,而是一个平级之间的互相流动.

<13>在其实现的show函数中,因为设计要求在Menu显示出来前,还要先保证另外的组件显示出来,
因此封装了实际的显示逻辑到一个runnable中,做为一个callback传入通知另外组件显示的event并发出去,在其他组件显示以后,
会调用此callback来显示TabMenu,不过是通过post的方式,因此也不算是同步调用.

<14>在真正tabMenu显示自己时, 会通知子View初始化并且移动到合适的位置,最后才会setVisibility(View.VISIBLE),
并且会把自己和子View SetEnabled(false), 这是因为真正Menu显示出来还要依靠MovingMenu对tabMenu进行scroll,
在这个过程完成之前,TabMenu应该是disable的,SetEnabled(true)会在Menu真正open end以后被调用<TabMenu监听了MovingMenu的这些
event>, 在Menu打开的过程中<就是MovingMenu调整TabMenu的位置时>,SetEnabled(false)还会被不断调用以保险.

<15>在Menu open这一过程结束以后, TabMenu会监听并做一些工作,因为这些操作都是在draw帧之前处理valueAnimator的时候被调用,
为了性能,这些操作后来被post delay,在这一帧draw以后再进行这些工作,保证显示的流畅性.
对于当前Active的Tab,在open end以后会进行一次tab 的 thumbnail的刷新,
在thubnail刷新以后,会收到event通知子View更新thumbnail.

<16>从信息流上看,TabMenu的角色类似一个UI的中间层,在上下层互通数据和event.
而因为TabMenu 会在外部被使用<它其实是对外部来说TabMenu这个概念的代表,他实现了TabMenuInterface的接口
,MovingMenu的角色更像一个外部包装,因此很多TabMenu的调用会转发给MovingMenu,之所以MovingMenu没有作为
TabMenu的代表,是因为MovingMenu的角色定位其实不是TabMenu这个概念.>,TabMenu其实反而是UI核心层.
Android因为和UI关系比较紧密的原因,在划分View的功能职责时,一般的思路是越外边的代表的概念越大,
尽量体现封闭性,不过上面这种某个中间UI层的View被抽出来作为概念的代表,也是一种做法.

<17>hide TabMenu会调用上层的MovingMenu hide,并将自己和子View disable, 设为INVISIBLE, 还接受一个runnable,最后会post这个runnable.

<18>TabMenu不是从头写的,是对原来的重构.

<19>Tab被移除也会监听,除了通告子View外,还会将Tab对应的TabView对应的thumbnail进行recycle.

<20>TabMenu的code一直比较混乱,重构做的也不彻底.


0 0
原创粉丝点击