diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/top/iletter/lvnote/BookListFragment.java b/app/src/main/java/top/iletter/lvnote/BookListFragment.java
new file mode 100644
index 0000000..6497729
--- /dev/null
+++ b/app/src/main/java/top/iletter/lvnote/BookListFragment.java
@@ -0,0 +1,65 @@
+package top.iletter.lvnote;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+import androidx.viewpager2.widget.ViewPager2;
+
+import com.google.android.material.tabs.TabLayout;
+import com.google.android.material.tabs.TabLayoutMediator;
+
+public class BookListFragment extends Fragment {
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_book_list, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ ViewPager2 viewPagerSecondary = view.findViewById(R.id.view_pager_secondary);
+ viewPagerSecondary.setAdapter(new SecondaryPagerAdapter(this));
+
+ TabLayout tabSecondary = requireActivity().findViewById(R.id.tab_secondary);
+ tabSecondary.setVisibility(View.VISIBLE);
+
+ new TabLayoutMediator(tabSecondary, viewPagerSecondary, (tab, position) -> {
+ switch (position) {
+ case 0: tab.setText("已读"); break;
+ case 1: tab.setText("在读"); break;
+ case 2: tab.setText("想读"); break;
+ }
+ }).attach();
+ }
+
+ static class SecondaryPagerAdapter extends FragmentStateAdapter {
+ public SecondaryPagerAdapter(@NonNull Fragment fragment) {
+ super(fragment);
+ }
+
+ @NonNull
+ @Override
+ public Fragment createFragment(int position) {
+ return MediaListFragment.newInstance(
+ position == 0 ? "read" :
+ position == 1 ? "reading" : "plan_to_read"
+ );
+ }
+
+ @Override
+ public int getItemCount() {
+ return 3;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/top/iletter/lvnote/FragmentHome.java b/app/src/main/java/top/iletter/lvnote/FragmentHome.java
index 13bfcce..3b570c9 100644
--- a/app/src/main/java/top/iletter/lvnote/FragmentHome.java
+++ b/app/src/main/java/top/iletter/lvnote/FragmentHome.java
@@ -8,14 +8,28 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
+import com.google.android.material.tabs.TabLayoutMediator;
public class FragmentHome extends Fragment {
+
+ private TabLayout tabMain;
+ private TabLayout tabSecondary;
+ private ViewPager2 viewPagerMain;
+
+ // 三个主页面
+ private final Fragment movieFragment = new MovieListFragment();
+ private final Fragment bookFragment = new BookListFragment();
+ private final Fragment noteFragment = new NoteListFragment();
+
+ @Nullable
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
@@ -23,14 +37,67 @@ public class FragmentHome extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- TabLayout tabLayout = view.findViewById(R.id.tab_layout);
- ViewPager2 viewPager = view.findViewById(R.id.view_pager);
+ tabMain = view.findViewById(R.id.tab_main);
+ tabSecondary = view.findViewById(R.id.tab_secondary);
+ viewPagerMain = view.findViewById(R.id.view_pager_main);
- // 设置三标签:看过/正在看/准备看
- tabLayout.addTab(tabLayout.newTab().setText("看过"));
- tabLayout.addTab(tabLayout.newTab().setText("正在看"));
- tabLayout.addTab(tabLayout.newTab().setText("准备看"));
+ // 设置外层 ViewPager2 适配器
+ viewPagerMain.setAdapter(new MainPagerAdapter(this));
- // TODO: 后续实现 ViewPager2 适配器
+ // 绑定一级导航
+ new TabLayoutMediator(tabMain, viewPagerMain, (tab, position) -> {
+ switch (position) {
+ case 0:
+ tab.setText("观影记");
+ break;
+ case 1:
+ tab.setText("书摘");
+ break;
+ case 2:
+ tab.setText("随笔");
+ break;
+ }
+ }).attach();
+
+ // 一级 Tab 切换监听(控制二级导航显示/隐藏)
+ tabMain.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
+ @Override
+ public void onTabSelected(TabLayout.Tab tab) {
+ // 随笔页面隐藏二级导航
+ if (tab.getPosition() == 2) {
+ tabSecondary.setVisibility(View.GONE);
+ } else {
+ tabSecondary.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onTabUnselected(TabLayout.Tab tab) {}
+
+ @Override
+ public void onTabReselected(TabLayout.Tab tab) {}
+ });
+ }
+
+ // 外层 ViewPager2 适配器
+ static class MainPagerAdapter extends FragmentStateAdapter {
+ public MainPagerAdapter(@NonNull Fragment fragment) {
+ super(fragment);
+ }
+
+ @NonNull
+ @Override
+ public Fragment createFragment(int position) {
+ switch (position) {
+ case 0: return new MovieListFragment();
+ case 1: return new BookListFragment();
+ default: return new NoteListFragment();
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return 3;
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/top/iletter/lvnote/FragmentProfile.java b/app/src/main/java/top/iletter/lvnote/FragmentProfile.java
index ae98153..2c2d94e 100644
--- a/app/src/main/java/top/iletter/lvnote/FragmentProfile.java
+++ b/app/src/main/java/top/iletter/lvnote/FragmentProfile.java
@@ -12,7 +12,6 @@ import androidx.fragment.app.Fragment;
public class FragmentProfile extends Fragment {
- // ⚠️ 必须有无参构造函数!
public FragmentProfile() {
// Required empty public constructor
}
@@ -33,7 +32,7 @@ public class FragmentProfile extends Fragment {
TextView movieCount = view.findViewById(R.id.tv_movie_count);
TextView bookCount = view.findViewById(R.id.tv_book_count);
- if (movieCount != null) movieCount.setText("24");
+ if (movieCount != null) movieCount.setText("14");
if (bookCount != null) bookCount.setText("18");
}
}
\ No newline at end of file
diff --git a/app/src/main/java/top/iletter/lvnote/MediaAdapter.java b/app/src/main/java/top/iletter/lvnote/MediaAdapter.java
new file mode 100644
index 0000000..25c296d
--- /dev/null
+++ b/app/src/main/java/top/iletter/lvnote/MediaAdapter.java
@@ -0,0 +1,52 @@
+package top.iletter.lvnote;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+public class MediaAdapter extends RecyclerView.Adapter {
+
+ private final List items;
+
+ public MediaAdapter(List items) {
+ this.items = items;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_media, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ String[] parts = items.get(position).split(" · ");
+ holder.title.setText(parts[0]);
+ holder.meta.setText(parts.length > 1 ? parts[1] + " · " + parts[2] : "");
+ holder.rating.setText(position % 3 == 0 ? "9.7" : position % 3 == 1 ? "9.2" : "8.9");
+ }
+
+ @Override
+ public int getItemCount() {
+ return items.size();
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ TextView title, meta, rating;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ title = itemView.findViewById(R.id.tv_title);
+ meta = itemView.findViewById(R.id.tv_meta);
+ rating = itemView.findViewById(R.id.tv_rating);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/top/iletter/lvnote/MediaListFragment.java b/app/src/main/java/top/iletter/lvnote/MediaListFragment.java
new file mode 100644
index 0000000..e45e534
--- /dev/null
+++ b/app/src/main/java/top/iletter/lvnote/MediaListFragment.java
@@ -0,0 +1,89 @@
+package top.iletter.lvnote;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MediaListFragment extends Fragment {
+
+ private static final String ARG_STATUS = "status";
+ private String status;
+
+ public static MediaListFragment newInstance(String status) {
+ MediaListFragment fragment = new MediaListFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_STATUS, status);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ status = getArguments().getString(ARG_STATUS);
+ }
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_media_list, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ RecyclerView recyclerView = view.findViewById(R.id.recycler_media);
+ recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
+
+ // 模拟数据(根据状态返回不同假数据)
+ List items = generateFakeData(status);
+ MediaAdapter adapter = new MediaAdapter(items);
+ recyclerView.setAdapter(adapter);
+ }
+
+ private List generateFakeData(String status) {
+ List data = new ArrayList<>();
+ switch (status) {
+ case "watched":
+ data.add("肖申克的救赎 · 弗兰克·德拉邦特 · 1994");
+ data.add("阿甘正传 · 罗伯特·泽米吉斯 · 1994");
+ data.add("盗梦空间 · 克里斯托弗·诺兰 · 2010");
+ break;
+ case "watching":
+ data.add("权力的游戏 S08 · HBO · 2019");
+ data.add("怪奇物语 S04 · Netflix · 2022");
+ break;
+ case "plan_to_watch":
+ data.add("奥本海默 · 克里斯托弗·诺兰 · 2023");
+ data.add("沙丘2 · 丹尼斯·维伦纽瓦 · 2024");
+ break;
+ case "read":
+ data.add("三体 · 刘慈欣 · 2006");
+ data.add("活着 · 余华 · 1993");
+ break;
+ case "reading":
+ data.add("人类简史 · 尤瓦尔·赫拉利 · 2011");
+ break;
+ case "plan_to_read":
+ data.add("百年孤独 · 加西亚·马尔克斯 · 1967");
+ data.add("追风筝的人 · 卡勒德·胡赛尼 · 2003");
+ break;
+ }
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/top/iletter/lvnote/MovieListFragment.java b/app/src/main/java/top/iletter/lvnote/MovieListFragment.java
new file mode 100644
index 0000000..c7da612
--- /dev/null
+++ b/app/src/main/java/top/iletter/lvnote/MovieListFragment.java
@@ -0,0 +1,68 @@
+package top.iletter.lvnote;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+import androidx.viewpager2.widget.ViewPager2;
+
+import com.google.android.material.tabs.TabLayout;
+import com.google.android.material.tabs.TabLayoutMediator;
+
+public class MovieListFragment extends Fragment {
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_movie_list, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ ViewPager2 viewPagerSecondary = view.findViewById(R.id.view_pager_secondary);
+ viewPagerSecondary.setAdapter(new SecondaryPagerAdapter(this));
+
+ // 获取父 Fragment 的二级 TabLayout
+ TabLayout tabSecondary = requireActivity().findViewById(R.id.tab_secondary);
+ tabSecondary.setVisibility(View.VISIBLE);
+
+ // 绑定二级导航
+ new TabLayoutMediator(tabSecondary, viewPagerSecondary, (tab, position) -> {
+ switch (position) {
+ case 0: tab.setText("看过"); break;
+ case 1: tab.setText("正在看"); break;
+ case 2: tab.setText("准备看"); break;
+ }
+ }).attach();
+ }
+
+ // 二级 ViewPager2 适配器(三个状态页面)
+ static class SecondaryPagerAdapter extends FragmentStateAdapter {
+ public SecondaryPagerAdapter(@NonNull Fragment fragment) {
+ super(fragment);
+ }
+
+ @NonNull
+ @Override
+ public Fragment createFragment(int position) {
+ return MediaListFragment.newInstance(
+ position == 0 ? "watched" :
+ position == 1 ? "watching" : "plan_to_watch"
+ );
+ }
+
+ @Override
+ public int getItemCount() {
+ return 3;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/top/iletter/lvnote/NoteAdapter.java b/app/src/main/java/top/iletter/lvnote/NoteAdapter.java
new file mode 100644
index 0000000..0351682
--- /dev/null
+++ b/app/src/main/java/top/iletter/lvnote/NoteAdapter.java
@@ -0,0 +1,53 @@
+package top.iletter.lvnote;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+public class NoteAdapter extends RecyclerView.Adapter {
+
+ private final List notes;
+
+ public NoteAdapter(List notes) {
+ this.notes = notes;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_note, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ String note = notes.get(position);
+ String[] parts = note.split(" · ");
+ holder.title.setText(parts[0]);
+ holder.content.setText(parts.length > 1 ? parts[1] : "无内容");
+ holder.time.setText("2024-02-09 15:30");
+ }
+
+ @Override
+ public int getItemCount() {
+ return notes.size();
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ TextView title, content, time;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ title = itemView.findViewById(R.id.tv_note_title);
+ content = itemView.findViewById(R.id.tv_note_content);
+ time = itemView.findViewById(R.id.tv_note_time);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/top/iletter/lvnote/NoteListFragment.java b/app/src/main/java/top/iletter/lvnote/NoteListFragment.java
new file mode 100644
index 0000000..246941d
--- /dev/null
+++ b/app/src/main/java/top/iletter/lvnote/NoteListFragment.java
@@ -0,0 +1,54 @@
+package top.iletter.lvnote;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class NoteListFragment extends Fragment {
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_note_list, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ RecyclerView recyclerView = view.findViewById(R.id.recycler_notes);
+ TextView tvEmpty = view.findViewById(R.id.tv_empty);
+
+ recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
+
+ // 模拟笔记数据(空列表演示空状态)
+ List notes = Arrays.asList(
+ "2024-02-09 · 今日观影笔记",
+ "2024-02-08 · 读书随想",
+ "2024-02-05 · 生活碎片"
+ );
+
+ if (notes.isEmpty()) {
+ tvEmpty.setVisibility(View.VISIBLE);
+ recyclerView.setVisibility(View.GONE);
+ } else {
+ tvEmpty.setVisibility(View.GONE);
+ recyclerView.setVisibility(View.VISIBLE);
+ NoteAdapter adapter = new NoteAdapter(notes);
+ recyclerView.setAdapter(adapter);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_book_list.xml b/app/src/main/res/layout/fragment_book_list.xml
new file mode 100644
index 0000000..75b0b3b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_book_list.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 648879f..eccebbb 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -1,28 +1,39 @@
-
-
+
+ android:layout_height="48dp"
+ app:tabMode="fixed"
+ app:tabGravity="fill"
+ app:tabIndicatorColor="?colorPrimary"
+ app:tabIndicatorHeight="3dp"
+ app:layout_constraintTop_toTopOf="parent" />
-
-
+
+
-
-
-
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_media_list.xml b/app/src/main/res/layout/fragment_media_list.xml
new file mode 100644
index 0000000..167aade
--- /dev/null
+++ b/app/src/main/res/layout/fragment_media_list.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_movie_list.xml b/app/src/main/res/layout/fragment_movie_list.xml
new file mode 100644
index 0000000..750d777
--- /dev/null
+++ b/app/src/main/res/layout/fragment_movie_list.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_note_list.xml b/app/src/main/res/layout/fragment_note_list.xml
new file mode 100644
index 0000000..730c6b2
--- /dev/null
+++ b/app/src/main/res/layout/fragment_note_list.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_media.xml b/app/src/main/res/layout/item_media.xml
new file mode 100644
index 0000000..c71bad8
--- /dev/null
+++ b/app/src/main/res/layout/item_media.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_note.xml b/app/src/main/res/layout/item_note.xml
new file mode 100644
index 0000000..790f38e
--- /dev/null
+++ b/app/src/main/res/layout/item_note.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7dea023..0fd6b88 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -12,6 +12,8 @@
看过
正在看
准备看
+
+
添加影视
添加书籍
\ No newline at end of file