学习在于实用,只有把自己学到的东西真正的融入到我们的开发中,并且使用的得心应手,那才是真正的掌握。而想把技术使用的得心应手并不是一蹴而就的,需要不断的巩固自己的知识体系,需要大量的实战练习,当然还不能缺少你的专研和耐心。
但是很多小伙伴们并不一定学过的知识都掌握了,而且相信很多伙伴们即使学习一种技术也还是停留在读过,看过,学习过,并没有真正的实战过,所以当时学习的技术觉得自己真正的学会了,搞懂了,而且信心满满的觉得自己可以不必在练习了,这是不对的,因为一时的学习并没有立马转变成为你的技能,而是需要多次的巩固,再次的练习,继而能够拓展出新花样,那才证明你真正的掌握了。
所以创建了这个系列的博文,该博文主要是以一个完整的项目作为实战,以项目的进展作为向导,分析每个功能的实现,以及针对这个功能的我思我想,当然博主也是个小菜鸟,真实的意图是想通过这个小项目来记录自己的学习过程,并且,恳求各位大神,在每个功能实现的过程中,请在评论中贡献您的想法,或是觉得我所使用的方法或逻辑并不是恰当的、最好的,那么请把想法写进评论中,既作为您对该功能实现的看法,也可以提供我思路,给我们一起提升的机会,在这拜谢各位大大。
博主一直以来很喜欢动漫,可以说是酷爱了,所以这次就想以一个动漫的APP做为项目的开发,并请了一位非设计专业同事看了几部其他动漫APP利用闲暇时间,给整理出来一些共同点且是大多功能以后大家都会遇到的东西,简易的画个了原图,非常感谢这位同事,下面上图看看我们的原形需求。
相信大家一看就会明白,APP确实还是挺简单的,但是所需要的功能以后大家可能都会碰到,那时你会怎么设计呢?怎么找出共同点呢?
好,原图已上,让我们来看看整体设计吧,首先大家可以看到整个APP有很多相似之处,比如说顶端有两个选择项,中间是不同的布局,下面又是相同的底部菜单。所以我们可能自然而然的就想到,统一的底部菜单 + 中间FrameLayout布局 + toolBar就可以搞定了,是不是很简单呢。
今天我们就先来实现APP底部菜单栏的UI显示,底部菜单UI展现,以我们的需求可以通过好几种方式实现,比如使用:TabHost + ActivityGroup(已过时),Fragment + RadioGroup,Fragment + FragmentTabHost等几种选择,由于ActivityGroup已过时,TabHost 也逐渐被Fragment 所取代,所以项目我们选择Fragment + FragmentTabHost来实现我们的底部菜单。
Fragment 和 FragmentTabHost 都是android.support.v4.app包下的类,所以我们再使用是首先要先导入正确的包,而在XML文件中我们需要如下使用:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<android.support.v4.app.FragmentTabHost
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
</android.support.v4.app.FragmentTabHost>
</LinearLayout>
我们定义垂直方向的LinearLayout布局,FrameLayout用来显示我们的只要内容,FragmentTabHost用来在底部显示菜单。
ok,布局文件已配置好了,下面可考虑怎么加载到Acitivity中,在这之前,我习惯先创建一个Application,里面封装一个全局的Context变量,如:
public class MyApplication extends Application{
private static Context mContext;//全局获取context
@Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
/**
* 获取全局context
*/
public static Context getContext(){
return mContext;
}
}
还有先定义一个BaseActivity作为其他Activity的父类,并且把获取全部的资源方法封装进去。
public class BaseActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public static Context getContext(){
return SanHuiAppsAnimationApplication.getContext();
}
public static int getLayoutId(Context context, String paramString) {
return context.getResources().getIdentifier(paramString, "layout", context.getPackageName());
}
public static int getStringId(Context context, String paramString) {
return context.getResources().getIdentifier(paramString, "string", context.getPackageName());
}
public static int getDrawableId(Context context, String paramString) {
return context.getResources().getIdentifier(paramString, "drawable", context.getPackageName());
}
public static int getStyleId(Context context, String paramString) {
return context.getResources().getIdentifier(paramString, "style", context.getPackageName());
}
public static int getId(Context context, String paramString) {
return context.getResources().getIdentifier(paramString, "id", context.getPackageName());
}
public static int getMenuId(Context context, String paramString) {
return context.getResources().getIdentifier(paramString, "menu", context.getPackageName());
}
public static int getColorId(Context context, String paramString) {
return context.getResources().getIdentifier(paramString, "color", context.getPackageName());
}
public static int getLayoutId(String paramString) {
return getLayoutId(getContext(), paramString);
}
public static int getStringId(String paramString) {
return getStringId(getContext(), paramString);
}
public static int getDrawableId(String paramString) {
return getDrawableId(getContext(), paramString);
}
public static int getStyleId(String paramString) {
return getStyleId(getContext(), paramString);
}
public static int getId(String paramString) {
return getId(getContext(), paramString);
}
public static int getMenuId(String paramString) {
return getMenuId(getContext(), paramString);
}
public static int getColorId(String paramString) {
return getColorId(getContext(), paramString);
}
public static int getAnimId(String paramString) {
return getContext().getResources().getIdentifier(paramString, "anim", getContext().getPackageName());
}
public static int getAttrId(String paramString) {
return getContext().getResources().getIdentifier(paramString, "attr", getContext().getPackageName());
}
public static int getInterpolator(String name) {
return getContext().getResources().getIdentifier(name, "interpolator", getContext().getPackageName());
}
public static int getDimenId(String paramString) {
return getContext().getResources().getIdentifier(paramString, "dimen", getContext().getPackageName());
}
}
好,准备工作已完成,,现在来看看怎么把我们的刚才的main.xml添加到MainActivity中,并实现底部菜单的切换。
public class MainActivity extends FragmentActivity{
private FragmentTabHost mFragmentTabHost;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(BaseActivity.getLayoutId("activity_main"));
mFragmentTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
//初始化FragmentTabHost
mFragmentTabHost.setup(this,getSupportFragmentManager(),BaseActivity.getId("realtabcontent"));
addTabView("Collection", BaseActivity.getDrawableId("main_tab_item_collection"), CollectionFragment.class);
addTabView("Animation", BaseActivity.getDrawableId("main_tab_item_animation"), AnimationFragment.class);
addTabView("Game", BaseActivity.getDrawableId("main_tab_item_game"), GameFragment.class);
addTabView("Mine", BaseActivity.getDrawableId("main_tab_item_mine"), MineFragment.class);
}
public void addTabView(String viewTag, int iconId, Class<?> cls) {
View viewTabWidget = getTabWidget(iconId);
TabHost.TabSpec tabSpec = mFragmentTabHost.newTabSpec(viewTag);
tabSpec.setIndicator(viewTabWidget);
mFragmentTabHost.addTab(tabSpec,cls,null);
}
public View getTabWidget(int iconId) {
View viewTabWidget = LayoutInflater.from(this).inflate(BaseActivity.getLayoutId("activity_main_tabwidget"), null);
ImageView view = (ImageView) viewTabWidget.findViewById(BaseActivity.getId("tab_label"));
view.setImageResource(iconId);
return viewTabWidget;
}
}
其实很简单,首先,是通过获取资源文件并绑定FragmentTabHost,其中值得注意的是:
mFragmentTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);这个是从android.R.id.tabhost获取,main.xml也是这么给出的id,不要搞混了。
然后,通过得到所支持的FragmentManager来初始化FragmentTabHost,并绑定用于显示正文的Fragment。
再次,我们通过addTabView()方法把底部菜单所需要的View展示出来,这里使用的是TabHost.TabSpec,它需要一个标示几个参数,一个是tag标示,一个是用于底部菜单显示的view等,可以自己选择设置。这里的菜单View我是用xml文件selector选择器来自动选择的,因为四个底部菜单所用一样,这里就只贴出一个供参考:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/main_tab_collection" android:state_selected="false"/>
<item android:drawable="@mipmap/main_tab_collection_h" android:state_selected="true"/>
</selector>
最后,我们通过mFragmentTabHost.addTab(tabSpec,cls,null);把底部菜单和与之相关联的Fragment关联起来,从而达到在我们点击底部菜单时显示与之相对应的正文内容。
ok,底部菜单这块已基本实现,下面来看看效果吧。
好了,大家也看到了效果,那么就请大家在评论区发表下意见,或许你的实现方式更好呢,共同学习才能更快进步,谢谢大家。
更多资讯请关注微信平台,有博客更新会及时通知。爱学习爱技术。