资源描述
今年暑假我和一群朋友参加了某金融软件开发比赛。我们团队打算制定一个基于条形码的移动支付解决方案(点子诞生于5月份的一天,后来我们发现想做的东西已经有了一oogleWallet。囧),软件系统为C/S架构,我负责手机客户端部分。考虑到开放性和技术门槛我们选择了Android平台。虽然以前也写过一点Android程序,但绝大多数都是所谓的“玩具”,没什么实质性用途。因此,这些玩具们无不例外地拥有着极其简陋的界面。几乎所有的控件都是原生态,纯纯的Android两年前,当Android刚出道不久,当各种入门书籍还在漫天飞舞的时候,一款软件穿着原生控件走出去还稍显神气,毕竟那时成型的应用很少。但是,两年后,在这个绿色机器人摧城拔寨之时,如果一款Android应用没有好用、漂亮的UI,你都不好意思说自己在做Android应用开发。我觉得如果不在原有控件的基础上做一定的拓展,想要写出优美的界面是难以想象的。我们团队的软件很大程度上参考了Twitter,淘宝一类的客户端。我们想在屏幕底部弄一个标签栏(Tabs),这样用户就可以很方便地在不同的页面间切换了。作为Android新手,我当时只知道一种方法:使用Android自带的TabHost容器。传统的TabHost的使用效果大概是这样的(左图)这是大众点评网早期的Android客户端,标签栏使用了系统自带的控件。然而这个效果和我们看到的很多底部标签栏相差甚远(右图,twitter客户端Twidroyd截图)。他们到底是怎么实现的呢?为此,我在网上查了不少资料,大致有以下种方案:1.ButtonBar实现;2.修改TabWidget。1.ButtonBar基本思路:用一个Layout来呈现整个标签栏,在上面添加若干按钮作为标签,整个Layout作为一个部件include到各个界面的布局里去。当用户点击按钮时,切换到相应的界面(多个Activity间的切换)。在Android3.0以前的版本里,这种方案多用于制作动作栏。3.0后出现了ActionBar控件,为开发者省了不少事。希望手机版的Android也早点加入。优点:实现了你想要的效果,外观很容易定制。缺点:标签栏实际不是一个,有多个,他们分别属于不同的界面(从属关系)这导致了在界面切换的时候,标签栏会随着他的界面(或者说Activity)“动”,而非常驻在底部。改进:有一种改进方式是,用一个Activity来控制整个主界面,标签栏include在这个主界面的布局里,点击标签时显示相应的View(实际上是在一个Activity上多个View的切换)。这样就保证了标签栏只有一个,而且不会随着标签切换而动来动去。当然,缺点也是显而易见的,当标签过多的时候,这个Activity会变得相当复杂。呵呵万一有个变动,你懂的。修改TabWidget基本思路:在于既然Android是开源的,我们就能大改特该,让它听话。我们把TabWidget移到底部,然后修改它的外观。优点:达到了目的,继承了TabWidget的基本功能,可复用,使用简单;缺点:需要研究不少Android资料,查references查到眼花,费九牛二虎之力去掉分割线,底部白线之类的东西,完成外观定制。这个方法貌似有不少人用,这里有几篇中文资料(其实都差不多啦,中文圈你抄我我抄你的。唉):我想到了Android控件的一个属性:android:visibility=”gone”。这简直就是救命稻草!它可以让你的控件不显示,而且还不占地方。这有什么用呢?这意味着,我们可以照样用TabHost,可以照样放TabWidget,只是,只是我们不把TabWidget显示出来。它现在是隐形的标签栏,therealtabs。我们所要做的是:安置一个“傀儡”标签栏,让它来和用户接触。这是不是有点像DesignPattern里的“Proxy”呢?这个方案算是投机取巧之作,很可惜,我不是第一个想到的,你可以看这里。历史总是惊人的相似啊!标签容器布局,大致代码如下:main.xml:1 4043!-注意:id=id/tabl,为什么不是+id呢?这个和加载先454748495051525354555657585960616263646566676869707172737475767778android:tag=tab1android:layout_width=fill_parentandroid:layout_height=fill_parentandroid:layout_weight=1.0android:layout_marginTop=1.0dipandroid:text=Tab1android:button=nullandroid:gravity=centerandroid:background=drawable/tab_bg_selector/RadioGroup就是底部的标签栏,背景进行了自定义。我在这边demo里用了9.png格式的图嗯,你会经常用它的。此外,标签被选中和未被选中的关键在于android:background=”drawable/tab_bg_selector”这句。selector:selectorxmlns:android二26 publicclassTabDemoActivityextendsTabActivity2privateTabHosttabhost;privateRadioGrouptabGroup;5OverridepublicvoidonCreate(BundlesavedInstanceState)8super.onCreate(savedInstanceState);setContentView(R.layout.main);11tabhost=getTabHost();tabGroup=(RadioGroup)findViewById(R.id.tab_group);14/这里新建3个的Intent用于Activity的切换Intenttab1=newIntent(this,TabOneActivity.class);Intenttab2=newIntent(this,TabTwoActivity.class);Intenttab3=newIntent(this,TabThreeActivity.class);19/向tabhost里添加tabtabhost.addTab(tabhost.newTabSpec(TAB1).setIndicator(Tab221).setContent(tab1);tabhost.addTab(tabhost.newTabSpec(TAB2).setIndicator(Tab252).setContent(tab2);tabhost.addTab(tabhost.newTabSpec(TAB3).setIndicator(Tab283)29303132.setContent(tab3);/给各个按钮设置监听tabGroup.setOnCheckedChangeListener(new33OnTabChangeListener();34353637privateclassOnTabChangeListenerimplements38OnCheckedChangeListener394041424344454647484950515253545556OverridepublicvoidonCheckedChanged(RadioGroupgroup,intid)/TODOAuto-generatedmethodstub/尤其需要注意这里,setCurrentTabByTag方法是纽带switch(id)caseR.id.tab1:tabhost.setCurrentTabByTag(TAB1);break;caseR.id.tab2:tabhost.setCurrentTabByTag(TAB2);break;caseR.id.tab3:tabhost.setCurrentTabByTag(TAB3);break;最后,为演示起见我们写3个装入容器的Activity。TabOneActivity,TabTwoActivity,TabThreeActivity.比如TabOneActivity:publicclassTabOneActivityextendsActivity2OverrideprotectedvoidonCreate(BundlesavedInstanceState)/TODOAuto-generatedmethodstubsuper.onCreate(savedInstanceState);setContentView(R.layout.content);TextViewtext=(TextView)findViewById(R.id.text);text.setText(Thisistab1.);1012他们的layout很简单,在LinearLayout里就放了个TextView。这里就不贴了。最终效果图:Android自定义标签栏当然这只是一个Demo,要做得更漂亮你需要在细节处好好作文章,譬如,美化文字,添加图标等等。题外话:我觉得美工是你绝对不能忽视的问题,因为没有优秀的图片,你做出来的东西看上去要多渣就有多渣。你弄不出高光效果,你弄不好优雅的渐变,更做不出漂亮的图标。程序猿们,还在觉得自己比美工高级么?呵呵。
展开阅读全文