2. 欢迎模块
上一节对整个项目进行了综述(可参见 1. 项目综述 进行了解),接下来将从欢迎模块开始详细介绍。
知识点:
- 掌握欢迎界面的开发
- 主界面的标题栏
- 底部导航栏模块的开发,能够搭建底部导航栏
1. 欢迎界面
任务综述:
在实际开发中,开启应用程序时首先会呈现一个欢迎界面。此界面主要用于展示产品LOGO和公司的新闻信息。
1.1 欢迎界面
任务实施:
(1)创建项目。
指定包名为com.XXXX.newsdemo 。
(2)导入界面图片。
切换到Project选项卡/res中创建一个drawable-hdpi文件夹/导入背景图片;项目的icon图标导入mipmap-hdpi文件夹。
(3)创建欢迎界面。
类名为SplashActivity,布局文件名activity_splash。
activity_splash.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/launch_bg" >
</RelativeLayout>
(4)添加一个无标题的样式。项目创建时所有界面默认的蓝色标题栏不够美观。
styles.xml
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
(5)修改清单文件。项目需要设置自己的图标与无标题栏的样式,因此需要修改清单文件中<application>标签中的icon与theme属性。
android:icon="@mipmap/app_icon"
android:theme="@style/AppTheme.NoActionBar"
注意:
由于SplashActivity为程序的启动界面,因此需要在清单文件中设置启动界面对应的Activity为SplashActivity。
1.2 欢迎界面逻辑代码
任务分析:
欢迎界面主要展示产品LOGO与新闻信息,通常会在该界面停留一段时间后自动跳转到其他界面,因此需要在逻辑代码中设置欢迎界面暂停几秒(3秒)后再跳转。
任务实施:
创建init()方法,在该方法中使用Timer和TimerTask类设置欢迎界面延迟3s再跳转到主界面(MainActivity,此时为空白界面)。
SplashActivity.xml
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
init();
}
private void init() {
//利用Timer让此界面延迟3秒后再跳转,timer中有一个线程,这个线程不断执行task
Timer timer = new Timer();
//timertask实现runnable接口,TimerTask类表示一个在指定时间内执行的task
TimerTask task = new TimerTask() {
@Override
public void run() {
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
startActivity(intent);
SplashActivity.this.finish();
}
};
timer.schedule(task, 3000); //设置这个task在延迟三秒之后自动执行
}
}
2. 导航栏
任务综述:
项目中有一个底部导航栏,底部导航栏主要用于滑动切换不同的界面或者点击底部按钮时切换不同的界面,使用户操作比较方便便捷。
2.1 标题栏
任务分析:
在项目中都有一个“后退”键和一个标题。为了便于代码重复使用可以将“后退”键和标题抽取出来并单独放在一个布局文件(main_title_bar.xml)中。
标题栏界面
(1) 创建标题栏界面。
2个TextView:分别用于显示后退键(样式采用背景选择器的方式)和当前界面标题(界面标题暂未设置,需要在代码中动态设置),并设置标题栏背景透明。
main_title_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@android:color/transparent">
<TextView
android:id="@+id/tv_back"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/go_back_selector"
android:visibility="gone" />
<TextView
android:id="@+id/tv_main_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@android:color/white"
android:textSize="18sp" />
</RelativeLayout>
(2)创建背景选择器。标题栏界面中的返回键在按下(显示灰色图片)与弹起(显示白色图片)的状态切换它的背景图片,给用户带来动态效果。
go_back_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/iv_back_selected" android:state_pressed="true"/>
<item android:drawable="@drawable/iv_back"/>
</selector>
2.2 底部导航栏
任务分析:
此项目包含一个底部导航栏(即底部4个按钮),为了方便后续布局的搭建,创建一个底部导航栏UI的框架。
任务实施:
(1)导入界面图片(8张图)。
(2)放置界面布局。
在activity_main.xml中,通过<include>标签main_title_bar.xml(标题栏)引入。其中4个RadioButton控件用于显示底部按钮,1个ViewPager控件用户在加载每个底部按钮对应的界面后可以左右滑动。
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/main_title_bar"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="@android:color/white"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_home"
style="@style/style_RadioButton"
android:checked="true"
android:drawableTop="@drawable/rb_home_selector"
android:text="首页"
android:textColor="@drawable/rb_text_selector" />
<RadioButton
android:id="@+id/rb_count"
style="@style/style_RadioButton"
android:drawableTop="@drawable/rb_count_selector"
android:text="统计"
android:textColor="@drawable/rb_text_selector" />
<RadioButton
android:id="@+id/rb_video"
style="@style/style_RadioButton"
android:drawableTop="@drawable/rb_video_selector"
android:text="视频"
android:textColor="@drawable/rb_text_selector" />
<RadioButton
android:id="@+id/rb_me"
style="@style/style_RadioButton"
android:drawableTop="@drawable/rb_me_selector"
android:text="我"
android:textColor="@drawable/rb_text_selector" />
</RadioGroup>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/radioGroup" />
</RelativeLayout>
</LinearLayout>
(3)创建背景选择器。根据按钮被选中和未被选中的状态切换它的背景图片,给用户带来动态效果。当按钮未被选中时显示灰色图片,被选中时显示红色图片,以此类推其他3个背景选择器rb_count_selector.xml,rb_video_selector.xml,rb_me_selector.xml。
rb_home_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="true" android:drawable="@drawable/home_press"/>
<item android:state_checked="false" android:drawable="@drawable/home_normal"/>
</selector>
(4)创建文字颜色选择器。底部导航栏界面中的底部按钮所对应的文字颜色在按钮被选中与未被选中时也会有变化,因此同样需要创建一个背景选择器用于控制文字颜色,当按钮未被选中时文字颜色为灰色,当被选中时文字颜色为红色。
rb_text_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="true" android:color="@color/rdTextColorPress"/>
<item android:state_checked="false" android:color="@color/rdTextColorNormal"/>
</selector>
上诉文件中的rdTextColorPress、TextColorNormal两个颜色值写在colors.xml文件中,便于以后多次使用。
<color name="rdTextColorNormal">#999999</color>
<color name="rdTextColorPress">#eb413d</color>
(5)创建底部按钮的样式。由于底部导航栏的4个按钮具有相同的外观,因此需要为这4个按钮创建一个相同的样式,用于设置按钮的宽度、高度、比值、位置以及文字的大小。
styles.xml
<style name="style_RadioButton">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:button">@null</item>
<item name="android:background">@null</item>
<item name="android:layout_weight">1</item>
<item name="android:gravity">center</item>
<item name="android:layout_gravity">center</item>
<item name="android:textSize">12sp</item>
</style>
2.3 底部导航栏逻辑代码
任务分析:
在底部导航栏中点击不同的按钮或者滑动ViewPager控件加载的页面加载的页面会切换到不同的界面,因此需要为4个按钮设置选中状态的监听与ViewPager页面切换的监听。
任务实施:
(1)获取界面控件。MainActivity类中初始化方法initView(),用于获取标题栏、页面中间部分及底部导航栏界面所要使用到的控件,并设置RadioGroup选中状态的监听与ViewPager页面切换的监听。
(2)退出本应用。为了减少运行内存的占用,在不使用该应用时应该及时退出,因此需要在MainActivity中重写onKeyDown()方法,在该方法中调用System.exit()退出本应用。
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
private RadioGroup radioGroup;
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
private TextView tv_main_title;
private RelativeLayout rl_title_bar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
tv_main_title = (TextView) findViewById(R.id.tv_main_title);
tv_main_title.setText("首页");
rl_title_bar = (RelativeLayout) findViewById(R.id.title_bar);
rl_title_bar.setBackgroundColor(getResources().getColor(R.color.
rdTextColorPress));
radioGroup = (RadioGroup) findViewById(R.id.radioGroup);
//RadioGroup选中状态改变监听
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.rb_home:
//setCurrentItem()方法中第二个参数控制页面切换动画,true:打开,false:关闭
viewPager.setCurrentItem(0, false);
break;
case R.id.rb_count:
viewPager.setCurrentItem(1, false);
break;
case R.id.rb_video:
viewPager.setCurrentItem(2, false);
break;
case R.id.rb_me:
viewPager.setCurrentItem(3, false);
break;
}
}
});
viewPager = (ViewPager) findViewById(R.id.viewPager);
/**此处后续添加**/
//ViewPager页面切换监听
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int
positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
switch (position) {
case 0:
radioGroup.check(R.id.rb_home);
tv_main_title.setText("首页");
rl_title_bar.setVisibility(View.VISIBLE);
break;
case 1:
radioGroup.check(R.id.rb_count);
tv_main_title.setText("统计");
rl_title_bar.setVisibility(View.VISIBLE);
break;
case 2:
radioGroup.check(R.id.rb_video);
tv_main_title.setText("视频");
rl_title_bar.setVisibility(View.VISIBLE);
break;
case 3:
radioGroup.check(R.id.rb_me);
rl_title_bar.setVisibility(View.GONE);
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
protected long exitTime; //记录第一次点击时的时间
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK
&& event.getAction() == KeyEvent.ACTION_DOWN) {
if ((System.currentTimeMillis() - exitTime) > 2000) {
Toast.makeText(MainActivity.this, "再按一次退出黑马头条",
Toast.LENGTH_SHORT).show();
exitTime = System.currentTimeMillis();
} else {
MainActivity.this.finish();
System.exit(0);
}
return true;
}
return super.onKeyDown(keyCode, event);
}
}
此模块主要包括欢迎界面与底部导航栏,这两个界面相对比较简单。后续继续在路上~