Files
zhini_im/FollowFansActivity关注粉丝列表页面逻辑分析.txt
rw0067680 c01808ac21 first commit
Change-Id: Ib7c2ab10a2562044fcaf9879388a6cbc1db6ac61
2025-12-23 10:00:49 +08:00

556 lines
18 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FollowFansActivity 关注/粉丝列表页面逻辑分析
## 📋 概述
`FollowFansActivity` 是一个用于展示用户关注列表或粉丝列表的页面,支持下拉刷新和上拉加载更多功能。通过 `mType` 参数区分显示关注列表还是粉丝列表。
---
## 🎯 核心功能
1. **列表展示**:显示关注列表或粉丝列表
2. **分页加载**:支持分页加载更多数据
3. **下拉刷新**:支持下拉刷新列表
4. **上拉加载**:支持上拉加载更多
5. **关注操作**:在粉丝列表中可以直接关注未关注的用户
6. **用户详情**:点击头像查看用户详细信息
---
## 📊 页面类型mType
### 类型定义
```java
// 类型1=粉丝列表 2=关注列表 3=点赞列表(目前未使用)
```
### 页面标题
- **mType = "1"**:显示"我的粉丝"
- **mType = "2"**:显示"我的关注"
### 跳转入口
```java
// MeFragment.java 中跳转
// 关注列表
view.findViewById(R.id.ln_follow).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), FollowFansActivity.class);
intent.putExtra("mType", "2"); // 2=关注列表
intent.putExtra("user_id", userInfo.getUserId());
startActivity(intent);
}
});
// 粉丝列表
view.findViewById(R.id.ln_fans).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), FollowFansActivity.class);
intent.putExtra("mType", "1"); // 1=粉丝列表
intent.putExtra("user_id", userInfo.getUserId());
startActivity(intent);
}
});
```
---
## 🔄 完整业务流程
```
用户从MeFragment点击关注/粉丝
传递参数mType1或2、user_id
FollowFansActivity初始化
设置标题根据mType
初始化RecyclerView和Adapter
调用getPublish()获取第一页数据
显示列表数据
下拉刷新 → 重置页码为1 → 重新获取数据
上拉加载 → 页码+1 → 加载更多数据
点击头像 → 跳转UserInfoActivity
点击关注按钮 → 跳转InviteFriendActivity
```
---
## 📐 UI组件
### 布局文件
- **布局文件**`activity_follow_fans.xml`
- **主要组件**
- `Toolbar`:标题栏
- `SmartRefreshLayout`:下拉刷新和上拉加载容器
- `RecyclerView`:列表展示
### 列表项布局
- **布局文件**`adapter_follow_fans_item.xml`
- **显示内容**
- 头像(`img_ada_head`
- 昵称(`tv_ada_name`
- 粉丝数(`tv_ada_number`
- 关注按钮(`tv_ada_follow`
---
## 💾 数据模型
### GetFollowFansResult
```java
public class GetFollowFansResult extends StatusResult<GetFollowFansResult> {
private List<ListBean> list;
public static class ListBean {
private String id; // 用户ID
private String nickname; // 昵称
private String avatar; // 头像URL
private int gender; // 性别
private Object city; // 城市
private int fans_c; // 粉丝数
private boolean both_follow; // 是否互相关注
private String prevtime_text; // 上次活跃时间文本
private String logintime_text; // 登录时间文本
private String jointime_text; // 加入时间文本
}
}
```
### 关键字段说明
- **`both_follow`**:是否互相关注
- `true`:互相关注
- `false`:单向关注或未关注
---
## 🔧 核心方法
### 1. 初始化 (`bindEvents()`)
```java
@Override
protected void bindEvents() {
super.bindEvents();
// 获取Intent参数
mType = getIntent().getStringExtra("mType");
user_id = getIntent().getStringExtra("user_id");
// 根据类型设置标题
if ("1".equals(mType)){
setToolBarTitle("我的粉丝");
} else if ("2".equals(mType)){
setToolBarTitle("我的关注");
}
// 初始化RecyclerView
initRcyItem();
// 获取第一页数据
getPublish();
// 设置下拉刷新
swipeRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
mPage = 1; // 重置页码
getPublish(); // 重新获取数据
}
});
// 设置上拉加载
swipeRefreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
mPage++; // 页码+1
getPublish(); // 加载更多数据
}
});
}
```
**说明**
- 从Intent获取 `mType` 和 `user_id`
- 根据 `mType` 设置标题
- 初始化列表和刷新控件
---
### 2. 初始化RecyclerView (`initRcyItem()`)
```java
private void initRcyItem(){
rcy_item.setLayoutManager(new LinearLayoutManager(mContext));
mBaseAdapter = new BaseRcyAdapter(null, R.layout.adapter_follow_fans_item) {
@Override
public void bindView(@NonNull BaseViewHolder holder, int position) {
GetFollowFansResult.ListBean listBean = (GetFollowFansResult.ListBean) this.getmData().get(position);
// 1. 设置基本信息
holder.setText(R.id.tv_ada_name, listBean.getNickname());
holder.setText(R.id.tv_ada_number, listBean.getFans_c() + " 粉丝");
// 2. 设置头像
ImageView imageView = (ImageView) holder.getView(R.id.img_ada_head);
GlideUtils.loadRoundedCornerImage(mContext,
AppService.APP_FILE_ADDRESS + listBean.getAvatar(),
imageView);
// 3. 设置关注按钮状态根据mType和both_follow
TextView tvFollow = (TextView) holder.getView(R.id.tv_ada_follow);
if ("1".equals(mType)) {
// 粉丝列表:显示关注按钮状态
if (listBean.isBoth_follow()) {
// 互相关注
tvFollow.setTextColor(getResources().getColor(R.color.color_3333));
tvFollow.setBackground(getResources().getDrawable(R.drawable.btn_submit_qian_style));
holder.setText(R.id.tv_ada_follow, "互相关注");
} else {
// 未关注,显示关注按钮(可点击)
tvFollow.setTextColor(getResources().getColor(R.color.white));
tvFollow.setBackground(getResources().getDrawable(R.drawable.btn_submit_style));
holder.setText(R.id.tv_ada_follow, "关注");
holder.setOnClickListener(R.id.tv_ada_follow, new View.OnClickListener() {
@Override
public void onClick(View view) {
// 跳转到添加好友页面
UserViewModel userViewModel = ViewModelProviders.of(FollowFansActivity.this).get(UserViewModel.class);
UserInfo userInfo = userViewModel.getUserInfo(listBean.getId(), true);
if (userInfo == null) {
return;
}
Intent intent = new Intent(mContext, InviteFriendActivity.class);
intent.putExtra("userInfo", userInfo);
startActivity(intent);
}
});
}
} else if ("2".equals(mType)) {
// 关注列表:显示关注状态
if (listBean.isBoth_follow()) {
// 互相关注
tvFollow.setTextColor(getResources().getColor(R.color.color_3333));
tvFollow.setBackground(getResources().getDrawable(R.drawable.btn_submit_qian_style));
holder.setText(R.id.tv_ada_follow, "互相关注");
} else {
// 已关注(单向)
tvFollow.setTextColor(getResources().getColor(R.color.color_3333));
tvFollow.setBackground(getResources().getDrawable(R.drawable.btn_submit_qian_style));
holder.setText(R.id.tv_ada_follow, "已关注");
}
}
// 4. 点击头像查看用户详情
holder.setOnClickListener(R.id.img_ada_head, new View.OnClickListener() {
@Override
public void onClick(View view) {
UserViewModel userViewModel = ViewModelProviders.of(FollowFansActivity.this).get(UserViewModel.class);
UserInfo userInfo = userViewModel.getUserInfo(listBean.getId(), true);
if (userInfo == null) {
return;
}
Intent intent = new Intent(mContext, UserInfoActivity.class);
intent.putExtra("userInfo", userInfo);
startActivity(intent);
}
});
}
};
rcy_item.setAdapter(mBaseAdapter);
}
```
**关键逻辑**
#### 2.1 关注按钮状态(粉丝列表 mType="1"
- **互相关注** (`both_follow = true`)
- 显示"互相关注"
- 灰色背景,深色文字
- **不可点击**
- **未关注** (`both_follow = false`)
- 显示"关注"
- 蓝色背景,白色文字
- **可点击**:跳转到 `InviteFriendActivity` 添加好友
#### 2.2 关注按钮状态(关注列表 mType="2"
- **互相关注** (`both_follow = true`)
- 显示"互相关注"
- 灰色背景,深色文字
- **已关注** (`both_follow = false`)
- 显示"已关注"
- 灰色背景,深色文字
- **不可点击**(单向关注)
#### 2.3 点击头像
- 获取用户信息(`UserViewModel.getUserInfo()`
- 跳转到 `UserInfoActivity` 查看用户详情
---
### 3. 获取数据 (`getPublish()`)
```java
private void getPublish(){
HashMap<String,String> headParams = new HashMap<>();
// 类型1=粉丝列表 2=关注列表 3=点赞列表
headParams.put("type", mType);
headParams.put("page", mPage + "");
headParams.put("limit", AppService.PAGE_MAX_NUMBER + "");
headParams.put("user_id", user_id);
AppService.Instance().interactiveList(headParams, new SimpleCallback<GetFollowFansResult>() {
@Override
public void onUiSuccess(GetFollowFansResult result) {
// 结束刷新和加载更多
if (swipeRefreshLayout != null) {
swipeRefreshLayout.finishRefresh();
swipeRefreshLayout.finishLoadMore();
}
GetFollowFansResult data = result.getData();
if (mPage == 1) {
// 第一页:替换数据
if (data != null) {
ArrayList<GetFollowFansResult.ListBean> list =
(ArrayList<GetFollowFansResult.ListBean>) data.getList();
mBaseAdapter.setmData(list);
}
} else {
// 加载更多:追加数据
ArrayList<GetFollowFansResult.ListBean> list =
(ArrayList<GetFollowFansResult.ListBean>) data.getList();
mBaseAdapter.setLoadmData(list);
}
}
@Override
public void onUiFailure(int code, String msg) {
// 结束刷新和加载更多
if (swipeRefreshLayout != null) {
swipeRefreshLayout.finishRefresh();
swipeRefreshLayout.finishLoadMore();
}
showToast(msg);
}
});
}
```
**API信息**
- **接口路径**`/api/interactive/list``Api.interactiveList`
- **请求方法**POST
- **请求参数**
```java
{
"type": "1" 或 "2", // 类型1=粉丝列表2=关注列表
"page": "1", // 页码
"limit": "20", // 每页数量AppService.PAGE_MAX_NUMBER
"user_id": "用户ID" // 要查询的用户ID
}
```
**数据处理**
- **第一页** (`mPage == 1`):使用 `setmData()` 替换整个列表
- **加载更多** (`mPage > 1`):使用 `setLoadmData()` 追加数据到列表
---
## 🔄 刷新和加载更多
### 下拉刷新
```java
swipeRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
mPage = 1; // 重置页码为1
getPublish(); // 重新获取数据
}
});
```
**流程**
1. 用户下拉刷新
2. 重置页码为1
3. 调用 `getPublish()` 获取第一页数据
4. 使用 `setmData()` 替换列表数据
5. 调用 `swipeRefreshLayout.finishRefresh()` 结束刷新
### 上拉加载更多
```java
swipeRefreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
mPage++; // 页码+1
getPublish(); // 加载更多数据
}
});
```
**流程**
1. 用户上拉到底部
2. 页码+1
3. 调用 `getPublish()` 获取下一页数据
4. 使用 `setLoadmData()` 追加数据到列表
5. 调用 `swipeRefreshLayout.finishLoadMore()` 结束加载
---
## 🎨 UI状态说明
### 关注按钮样式
#### 1. 互相关注(灰色背景)
```java
tvFollow.setTextColor(getResources().getColor(R.color.color_3333)); // 深色文字
tvFollow.setBackground(getResources().getDrawable(R.drawable.btn_submit_qian_style)); // 灰色背景
holder.setText(R.id.tv_ada_follow, "互相关注");
```
- **显示**"互相关注"
- **状态**:不可点击
#### 2. 关注按钮(蓝色背景)
```java
tvFollow.setTextColor(getResources().getColor(R.color.white)); // 白色文字
tvFollow.setBackground(getResources().getDrawable(R.drawable.btn_submit_style)); // 蓝色背景
holder.setText(R.id.tv_ada_follow, "关注");
```
- **显示**"关注"
- **状态**:可点击(跳转到添加好友页面)
- **位置**仅在粉丝列表mType="1")中,且未关注时显示
#### 3. 已关注(灰色背景)
```java
tvFollow.setTextColor(getResources().getColor(R.color.color_3333)); // 深色文字
tvFollow.setBackground(getResources().getDrawable(R.drawable.btn_submit_qian_style)); // 灰色背景
holder.setText(R.id.tv_ada_follow, "已关注");
```
- **显示**"已关注"
- **状态**:不可点击
- **位置**在关注列表mType="2")中,且单向关注时显示
---
## 📝 关键字段和变量
### 成员变量
```java
private RecyclerView rcy_item; // 列表RecyclerView
private BaseRcyAdapter mBaseAdapter; // 列表适配器
private SmartRefreshLayout swipeRefreshLayout; // 下拉刷新控件
private int mPage = 1; // 当前页码
private String mType = ""; // 类型1=粉丝2=关注
private String user_id; // 用户ID
```
### Intent参数
- **`mType`**:类型("1"=粉丝列表,"2"=关注列表)
- **`user_id`**要查询的用户ID
---
## 🔗 关联页面
### 1. 跳转来源
- **`MeFragment`**:我的页面
- 点击"关注" → `mType="2"`
- 点击"粉丝" → `mType="1"`
### 2. 跳转目标
- **`UserInfoActivity`**:点击头像查看用户详情
- **`InviteFriendActivity`**:点击关注按钮添加好友(仅粉丝列表中未关注的用户)
---
## ⚠️ 注意事项
### 1. 数据分页
- 使用 `AppService.PAGE_MAX_NUMBER` 作为每页数量
- 第一页使用 `setmData()` 替换数据
- 后续页使用 `setLoadmData()` 追加数据
### 2. 刷新状态管理
- 请求成功后必须调用 `finishRefresh()` 和 `finishLoadMore()`
- 请求失败时也要调用,避免刷新控件一直显示
### 3. 用户信息获取
- 点击头像或关注按钮时,需要先通过 `UserViewModel.getUserInfo()` 获取用户信息
- 如果 `userInfo` 为 `null`,则不执行跳转
### 4. 关注按钮逻辑
- **粉丝列表**:未关注时显示可点击的"关注"按钮
- **关注列表**:所有项都显示状态(互相关注/已关注),不可点击
### 5. 状态栏设置
- 使用白色背景,深色图标:`setTitleBackgroundResource(R.color.white, false)`
---
## 📊 数据流程总结
```
用户操作
获取Intent参数mType, user_id
设置标题根据mType
初始化RecyclerView和Adapter
调用API获取第一页数据
显示列表(头像、昵称、粉丝数、关注状态)
用户交互:
- 下拉刷新 → 重置页码 → 重新获取
- 上拉加载 → 页码+1 → 追加数据
- 点击头像 → 查看用户详情
- 点击关注(粉丝列表) → 添加好友
```
---
## 🔍 相关文件
- **Activity**`uikit/src/main/java/cn/wildfire/chat/kit/user/FollowFansActivity.java`
- **布局文件**`uikit/src/main/res/layout/activity_follow_fans.xml`
- **列表项布局**`uikit/src/main/res/layout/adapter_follow_fans_item.xml`
- **数据模型**`uikit/src/main/java/cn/wildfire/chat/kit/net/model/GetFollowFansResult.java`
- **API服务**`uikit/src/main/java/cn/wildfire/chat/kit/net/AppService.java`
- **跳转来源**`app/src/main/java/com/xunpaisoft/social/im/main/MeFragment.java`
---
## 💡 技术要点
1. **SmartRefreshLayout**:用于下拉刷新和上拉加载
2. **BaseRcyAdapter**自定义的RecyclerView适配器
3. **分页加载**:通过页码控制数据加载
4. **条件渲染**:根据 `mType` 和 `both_follow` 显示不同的按钮状态
5. **Glide图片加载**:使用 `GlideUtils.loadRoundedCornerImage()` 加载圆角头像
6. **ViewModel获取用户信息**:使用 `UserViewModel` 获取用户信息用于跳转
---
## 📌 总结
`FollowFansActivity` 是一个功能完整的关注/粉丝列表页面,支持:
- ✅ 两种列表类型(关注/粉丝)
- ✅ 分页加载数据
- ✅ 下拉刷新和上拉加载更多
- ✅ 关注操作(粉丝列表)
- ✅ 用户详情查看
- ✅ 动态按钮状态显示
整个页面逻辑清晰,用户体验良好,代码结构合理。