主界面

目标

主要完成对主界面设计,可以点击底部导航栏的图标和文字来跳转到不同的界面

主界面如下

实现过程

初始化时使用AS自带的bottomnavigation来实现底部导航栏和界面之间的转换,每个界面都由一个Fragment来编写

布局文件

总体的xml文件:

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
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:itemIconTint="@color/blue"
app:menu="@menu/bottom_nav_menu" />

<fragment
android:id="@+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@id/nav_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />

</androidx.constraintlayout.widget.ConstraintLayout>

中间的图标对应的界面的xml文件,用RecyclerView来显示列表

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
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.exercises.exercisesFragment">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/RecyclerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/exercises_title"
tools:layout_editor_absoluteX="1dp"
tools:layout_editor_absoluteY="1dp" />

<TextView
android:id="@+id/exercises_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="移动设计开发习题"
android:gravity="center"
android:textColor="@color/white"
android:textSize="20sp"
android:background="@color/blue"
android:padding="20dp"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="158dp"
tools:layout_editor_absoluteY="5dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

每一个列表项目的xml文件

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
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/exercise_num"
android:layout_width="260dp"
android:layout_height="25dp"
android:text="共计5题"
app:layout_constraintTop_toBottomOf="@+id/exercise_name"
app:layout_constraintLeft_toLeftOf="@+id/exercise_name"
tools:layout_editor_absoluteX="108dp"
tools:layout_editor_absoluteY="81dp" />

<TextView
android:id="@+id/exercise_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="37dp"
android:layout_marginEnd="326dp"
android:background="@drawable/exercises_bg_1"
android:gravity="center"
android:text="1"
android:textColor="@color/white"
android:textSize="20sp"
android:layout_marginBottom="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="16dp" />

<TextView
android:id="@+id/exercise_name"
android:layout_width="260dp"
android:layout_height="25dp"
android:text="第一章 Android基础入门"
android:textSize="15sp"
android:textColor="@color/black"
app:layout_constraintTop_toTopOf="@id/exercise_id"
app:layout_constraintLeft_toRightOf="@+id/exercise_id"
android:layout_marginLeft="20dp"
tools:layout_editor_absoluteX="108dp"
tools:layout_editor_absoluteY="56dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

Java代码

总的Activity代码

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
package com.example.mytest;

import android.os.Bundle;

import com.google.android.material.bottomnavigation.BottomNavigationView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;

import com.example.mytest.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

private ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_course, R.id.navigation_exercises, R.id.navigation_my)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
NavigationUI.setupWithNavController(binding.navView, navController);
}

}

中间课程的Fragment代码,其余两个界面类似,对RecyclerView设置适配器

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
package com.example.mytest.ui.exercises;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.example.mytest.data.model.Item;
import com.example.mytest.R;
import com.example.mytest.ui.MyAdapter;

import java.util.ArrayList;

public class exercisesFragment extends Fragment {

private View view;//定义view用来设置fragment的layout
private String[] titles = {"第1章 Android基础入门","第2章 Android常见界面布局","第3章 Android常见界面控件","第4章 程序活动单元Activity",
"第5章 数据存储","第6章 内容提供者","第7章 广播机制","第8章 服务","第9章 网络编程","第10章 综合项目"};
public RecyclerView mMyRecyclerView;//定义RecyclerView
private ArrayList<Item> ItemList = new ArrayList<Item>();
//自定义recyclerveiw的适配器
private MyAdapter mMyRecyclerAdapter;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//获取练习fragment的layout
view = inflater.inflate(R.layout.fragment_dashboard, container, false);
//对recycleview进行初始化配置
initRecyclerView();
//初始化数据
initData();
return view;
}

/**
* TODO 初始化数据
*/
private void initData() {
for (int i=0;i<10;i++){
Item Item=new Item();
Item.Id=i+1+"";
Item.Name=titles[i];
ItemList.add(Item);
}
}

/**
* TODO 对recycleview进行初始化配置
*/

private void initRecyclerView() {
//获取RecyclerView
mMyRecyclerView=(RecyclerView)view.findViewById(R.id.RecyclerView);
//创建adapter
mMyRecyclerAdapter = new MyAdapter(getActivity(), ItemList);
//给RecyclerView设置adapter
mMyRecyclerView.setAdapter(mMyRecyclerAdapter);
//设置layoutManager,可以设置显示效果,是线性布局、grid布局,还是瀑布流布局
//参数是:上下文、列表方向(横向还是纵向)、是否倒叙
mMyRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
//设置item的分割线
mMyRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(),DividerItemDecoration.VERTICAL));
}

}

适配器如下

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package com.example.mytest.ui;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import com.example.mytest.data.model.Item;
import com.example.mytest.R;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.myViewHodler>{
private Context context;
private ArrayList<Item> ItemList;

//创建构造函数
public MyAdapter(Context context, ArrayList<Item> ItemList) {
//将传递过来的数据,赋值给本地变量
this.context = context;//上下文
this.ItemList = ItemList;//实体类数据ArrayList
}

/**
* 创建viewhodler,相当于listview中getview中的创建view和viewhodler
*
* @param parent
* @param viewType
* @return
*/
@Override
public myViewHodler onCreateViewHolder(ViewGroup parent, int viewType) {
//创建自定义布局
View itemView = View.inflate(context, R.layout.list, null);
return new myViewHodler(itemView);
}

/**
* 绑定数据,数据与view绑定
*
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(myViewHodler holder, int position) {
//根据点击位置绑定数据
Item data = ItemList.get(position);
holder.mItemName.setText(data.Name);//获取实体类中的name字段并设置
holder.mItemId.setText(data.Id);//获取实体类中的price字段并设置
switch (position%4){
case 0:holder.mItemId.setBackgroundResource(R.drawable.exercises_bg_1);break;
case 1:holder.mItemId.setBackgroundResource(R.drawable.exercises_bg_2);break;
case 2:holder.mItemId.setBackgroundResource(R.drawable.exercises_bg_3);break;
case 3:holder.mItemId.setBackgroundResource(R.drawable.exercises_bg_4);break;
}
}

/**
* 获取项目总数
*
* @return
*/
@Override
public int getItemCount() {
return ItemList.size();
}

//自定义viewhodler
class myViewHodler extends RecyclerView.ViewHolder {
private ImageView mItemImg;
private TextView mItemName;
private TextView mItemId;

public myViewHodler(View itemView) {
super(itemView);
mItemName = (TextView) itemView.findViewById(R.id.exercise_name);
mItemId = (TextView) itemView.findViewById(R.id.exercise_id);
//点击事件放在adapter中使用,也可以写个接口在activity中调用
//方法一:在adapter中设置点击事件
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//可以选择直接在本位置直接写业务处理
//Toast.makeText(context,"点击了xxx",Toast.LENGTH_SHORT).show();
//此处回传点击监听事件
if(onItemClickListener!=null){
onItemClickListener.OnItemClick(v, ItemList.get(getLayoutPosition()));
}
}
});

}
}

/**
* 设置item的监听事件的接口
*/
public interface OnItemClickListener {
/**
*
* @param view 点击的item的视图
* @param data 点击的item的数据
*/
public void OnItemClick(View view, Item data);
}

//需要外部访问,所以需要设置set方法,方便调用
private OnItemClickListener onItemClickListener;

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}

}

项目地址

github项目地址