Fork me on GitHub

手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(三)

点击查看上一篇文章:手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(二)

继上一篇我们的进一步封装,包含

  • OkhttpRequest
  • EventBus
  • Json解析,基类数据封装
  • ButterKnife

那么,这一篇,我准备加入:

  • BaseFragment
  • 精美的仿微信底部菜单栏
  • 网络请求失败时如何显示空View

继续来完善我们的快速开发框架。

1、开门见山,看下BaseFragment都做了些什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* Created by QHT on 2017-04-08.
*/
public abstract class BaseFragment extends Fragment
{
/**
* 依附的activity
*/
protected FragmentActivity mActivity;
/**
* 根view
*/
protected View mRootView;
@Override
@Nullable
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
if (getContentViewId() != 0) {
mRootView= inflater.inflate(getContentViewId(), null);
} else {
mRootView= super.onCreateView(inflater, container, savedInstanceState);
}
ButterKnife.bind(this, mRootView);
LogUtil.e(this.getClass().getName()+"--->onCreateView");
initData(getArguments());
return mRootView;
}
@Override
public void onAttach(Context context)
{
super.onAttach(context);
mActivity = getActivity();
}
/**
* 设置根布局资源id
* @return
*/
public abstract int getContentViewId();
/**
* 初始化数据
* @param arguments 接收到的从其他地方传递过来的参数
*/
protected void initData(Bundle arguments)
{
}
@Override
public void onResume() {
super.onResume();
LogUtil.e(this.getClass().getName()+"--->onResume");
}
@Override
public void onStop() {
super.onStop();
LogUtil.e(this.getClass().getName()+"--->onStop");
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtil.e(this.getClass().getName()+"--->onDestroy");
}
}

很简单,做了一些初始化操作。我们的子Fragment只需要继承并重写2个方法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class FragmentSecond extends BaseFragment {
@Override
public int getContentViewId() {
return R.layout.fragment_second;
}
@Override
protected void initData(Bundle arguments) {
super.initData(arguments);
}
}

因为暂时我们没有用到viewpage,所以不需要懒加载,等下面用到了的时候再加进去。

2、接下来看看我们的仿微信底部菜单栏是怎么做的?
MainActivity的布局呢,就是上面一个toolbar,中间一个Linearlayout用来显示Fragment,下面一个Ralativelayout容纳4个按钮

首先,初始化我们的Fragment状态,第一个fragment为默认加载的Fragment

这里写图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 初始化底部标签
*/
private void initTab() {
if (oneFragment == null) {
/** 默认加载第一个Fragment*/
oneFragment = new FragmentFrist();
}
if (!oneFragment.isAdded()) {
/** 如果第一个未被添加,则添加到管理器中*/
getSupportFragmentManager().beginTransaction()
.add(R.id.content_layout, oneFragment).commit();
/** 记录当前Fragment*/
currentFragment = oneFragment;
/** 设置图片文本的变化*/
llBottomIvOne.setImageResource(R.mipmap.bottom_home_click);
llBottomTvOne.setTextColor(getResources()
.getColor(R.color.bottom_click));
llBottomIvTwo.setImageResource(R.mipmap.bottom_notice_normal);
llbottomTvTwo.setTextColor(getResources().getColor(
R.color.bottom_normal));
llBottomIvThree.setImageResource(R.mipmap.bottom_bill_normal);
llBottomTvThree.setTextColor(getResources().getColor(
R.color.bottom_normal));
llBottomIvFour.setImageResource(R.mipmap.bottom_me_normal);
llBottomTvFour.setTextColor(getResources().getColor(
R.color.bottom_normal));
}
}

接下来,当我们点击底部每个按钮时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 点击第一个tab
*/
private void clickTab1Layout() {
if (oneFragment == null) {
oneFragment = new FragmentFrist();
}
addOrShowFragment(getSupportFragmentManager().beginTransaction(), oneFragment);
llBottomIvOne.setImageResource(R.mipmap.bottom_home_click);
llBottomTvOne.setTextColor(getResources()
.getColor(R.color.bottom_click));
llBottomIvTwo.setImageResource(R.mipmap.bottom_notice_normal);
llbottomTvTwo.setTextColor(getResources().getColor(
R.color.bottom_normal));
llBottomIvThree.setImageResource(R.mipmap.bottom_bill_normal);
llBottomTvThree.setTextColor(getResources().getColor(
R.color.bottom_normal));
llBottomIvFour.setImageResource(R.mipmap.bottom_me_normal);
llBottomTvFour.setTextColor(getResources().getColor(
R.color.bottom_normal));
}

这个方法用来判断到底是add还是show/hide 我们的Fragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 添加或者显示碎片
*
* @param transaction
* @param fragment
*/
private void addOrShowFragment(FragmentTransaction transaction,
Fragment fragment) {
if (currentFragment == fragment)
return;
if (!fragment.isAdded()) {
// 如果当前fragment未被添加,则添加到Fragment管理器中
transaction.hide(currentFragment)
.add(R.id.content_layout,
fragment).commit();
} else {
// 如果当前fragment已被添加,则显示即可
transaction.hide(currentFragment).show(fragment).commit();
}
currentFragment = fragment;
}

3、再来看看我们的空View是怎么实现的呢?

在使用listview时我们见过 setEmptyView() 方法(内部实现原理也是通过 Visible 去控制显示的),但是其他的 view 却没有吧,因此我们实现一个自己的空 View,在什么时候都可以使用。
这里写图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class EmptyViewLayout extends RelativeLayout {
private ImageView failure;//加载失败的图片
private View bindView;// 绑定的View,即要显示的View
private Button loading_btn;//重试按钮
public EmptyViewLayout(Context context) {
super(context);
initView(context);
}
public EmptyViewLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.empty_view,null);
failure = (ImageView)view.findViewById(R.id.loading_failure);
loading_btn= (Button) view.findViewById(R.id.loading_btn);
//设置View参数
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
//最后添加进ViewGroup
addView(view, param);
}
/**
*正在加载中
*/
public void Loading() {
setVisibility(View.VISIBLE);
if (bindView != null) {
failure.setVisibility(View.GONE);
loading_btn.setVisibility(View.GONE);
}
}
/**
*加载成功
*/
public void succees() {
setVisibility(View.GONE);
if (bindView != null) {
bindView.setVisibility(View.VISIBLE);
}
}
/**
*加载失败
*/
public void failure() {
setVisibility(View.VISIBLE);
if (bindView != null) {
failure.setVisibility(View.VISIBLE);
bindView.setVisibility(View.GONE);
loading_btn.setVisibility(View.VISIBLE);
}
}
// 绑定加载 的view
public void bindView(View view) {
this.bindView = view;
}
/*
* 利用反射机制,响应对方需要响应的方法
*/
public void buttonClick(final Object base, final String method) {
loading_btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
Method m=base.getClass().getDeclaredMethod(method);
m.setAccessible(true);
m.invoke(base, null);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

在布局和Activity中我们这样使用:

1
2
3
4
5
6
7
8
/**
*布局中
*/
<com.qht.blog2.View.EmptyViewLayout
android:id="@+id/emptyView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
*Activity中
*/
// 绑定要显示的View
emptyView.bindView(content);
// 注册点击事件,加载失败后点击重试执行onload方法
emptyView.buttonClick(this, "onClick");
在我们的onResponse中执行 emptyView.succees();方法
在我们的onError中执行 emptyView.succees();方法
在我们的onBefore中执行 emptyView.Loading();方法

原理就是利用View的Visible和Gone去控制显示哪个View。


下一篇,我准备开始实现功能了:
(因为我们刚开始选用的接口为快递100的,所以功能上考虑为一款快递查询APP)

  • Fragment 和 ViewPage 结合实现顶部标签切换
  • RecycleView 实现精美的订单追踪页面

我的QQ: 1003077897
我的csdn:http://blog.csdn.net/u012534831
我的github:https://github.com/qht1003077897/AppFrame
我的个人博客:https://qht1003077897.github.io

欢迎交流。