Wallpaper模块(2):

WallPaperFragment extends ButtonReceiveFragment,
后者是项目的一个基础类,作用很简单,在被attach到某个Actviity时,如果Actviity
是一个ButtonProvider<也是项目实现,提供对onKeyDown/Up..的通告>,那么该fragment<Receiver>就会将自己register到该
Activity以在Activity收到onKeyDown时,会被通告并将自己popBackStackImmediate()<protected的,可以自己定制>.
这个baseClass的default实现的popBack功能是有点多余,在FragmentActivity本身就有这个逻辑,
不过这个baseClass的存在使得对于所有onKeyXXX事件的监听,是很有用的,在被Detach时会unregister。
WallPaperFragment比较简单,提供一个wallPagerList供用户选择,并且所选即所见,还提供了用户定制wallPaper<一部分逻辑>.
只记录一部分要点:

<1>wallpaper List直接用LinearLayout + HorizontalScrollView实现了,简单,虽然不如ListView那样会自动回收不可见的
View<convertView>, 不过考虑到这个List本身不长,所以接受.
List的每个Item也是一个复合View,动态从layout文件inflate然后addView.

<2>设计要求wallPaperList每次展现时都会自动scroll到当前被选中的wallpaper, 为了实现这个效果,这里使用了
ViewTreeOberver来检测wallPaperList的GlobalLayout<即代表List被重新的展现,比如旋转或者被attach到window或者尺寸变化>,
每次被layout<这一步callback晚于View的onLayout,但是够用>的时候就重新根据当前屏幕width/height,以及被选中的
wallPaper来计算应该scroll多少,并且将被选中的Item设为selected.
其实直接在onCreateView中这么做也可以,不过使用observer更为保险,View的size应该更准确一些,
onCreateView中得到的View的size不一定是最终呈现时的size.

<3>每次fragment的onCreateView时,都要重新根据持久化的wallpaperInfo重新生成一遍当前的wallpaper对应的Item并add到
List中<废话,每次onCreateView都是重新构造View>

<4>对于几个xml属性的使用:
(1)android:duplicateParentState,
一个包含了很多child的layout,有不同的selected/unselected状态,那么如果只改变layout的,下面的child的状态是不会被改变的,
如果code实现的话就比较麻烦,但是如果childView设了duplicateParentState="true",那么就可以自动复制parent的状态了.
(2)android:foreground, View的前景图<根据state不同有不同item>,
比如为了表示某个View被选中,会在这个View上面显示一个小图片表示被选中,
如果纯用辅助View+位移实现的话,会很麻烦。
foreground本身支持一个selector,根据不同的state<state_pressed/state_selected等以及自定义的>可以定制不同的drawable.很方便.

<5>善用View的tag:
(1)List里面的View都是动态inflate的,没有id,当然了可以通过setId来设置,不过setId有时候运气背可能正好和某个
现有的id冲突<id的具体数值是R类生成时决定的,id也只能是int>, 而在这些View被click时回调到onClick(View v),就无法判断哪个
View被click了,当然了你可以维护一份View引用和id的映射表,但是麻烦了点,这时候就可以使用View的tag了,
在inflate了View以后,就为该View set一个unique的tag,然后在onClick的时候取出tag<记住做类型转换>,根据tag就
可以知道哪个被点了.
这只是tag的一个小作用.

<6>目前设计和产品只要求保存一份自定义wallPaper,在List中显示的这一份自定义Bitmap是构造List Item时现裁剪的成的bitmap,
因此在每次detach时,都会手动将其recycle()<当然,不做后面也会释放,不过recycle这个函数能早跑就早跑>.