package com.tplink.trainingapp.clients.viewmodel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class ClientViewModel extends ViewModel {
// 主网络在线设备数量
private MutableLiveData<Integer> mainOnlineCount = new MutableLiveData<>(4);
// 主网络离线设备数量
private MutableLiveData<Integer> mainOfflineCount = new MutableLiveData<>(3);
// 访客网络设备数量
private MutableLiveData<Integer> guestCount = new MutableLiveData<>(1);
// 刷新状态
private MutableLiveData<Boolean> isRefreshing = new MutableLiveData<>(false);
// 获取主网络在线设备数量
public LiveData<Integer> getMainOnlineCount() {
return mainOnlineCount;
}
// 获取主网络离线设备数量
public LiveData<Integer> getMainOfflineCount() {
return mainOfflineCount;
}
// 获取访客网络设备数量
public LiveData<Integer> getGuestCount() {
return guestCount;
}
// 获取刷新状态
public LiveData<Boolean> getRefreshingState() {
return isRefreshing;
}
// 刷新数据
public void refreshData() {
isRefreshing.setValue(true);
// 模拟网络请求延时
// 在实际项目中,这里应该是网络请求或数据库查询
new android.os.Handler().postDelayed(new Runnable() {
@Override
public void run() {
// 模拟数据变化
mainOnlineCount.setValue((int) (Math.random() * 5) + 1);
mainOfflineCount.setValue((int) (Math.random() * 4) + 1);
guestCount.setValue((int) (Math.random() * 3) + 1);
isRefreshing.setValue(false);
}
}, 1500);
}
// 更新主网络在线设备数量
public void updateMainOnlineCount(int count) {
mainOnlineCount.setValue(count);
}
// 更新主网络离线设备数量
public void updateMainOfflineCount(int count) {
mainOfflineCount.setValue(count);
}
// 更新访客网络设备数量
public void updateGuestCount(int count) {
guestCount.setValue(count);
}
// 获取当前主网络在线设备数量的值
public int getCurrentMainOnlineCount() {
Integer count = mainOnlineCount.getValue();
return count != null ? count : 0;
}
// 获取当前主网络离线设备数量的值
public int getCurrentMainOfflineCount() {
Integer count = mainOfflineCount.getValue();
return count != null ? count : 0;
}
// 获取当前访客网络设备数量的值
public int getCurrentGuestCount() {
Integer count = guestCount.getValue();
return count != null ? count : 0;
}
}
package com.tplink.trainingapp.clients.adapter;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.tplink.design.list.TPTwoLineItemView;
import com.tplink.design.list.TPTwoLineItemViewHolder;
import com.tplink.design.menu.TPPopupMenu;
import com.tplink.trainingapp.R;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ClientListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private int itemCount;
private Context context;
private boolean isOnlineAdapter; // 区分在线和离线adapter
// 模拟的设备数据
private String[] deviceNames = {"Melanie's iPhone", "Melanie's iMac", "Melanie's iPhone"};
private int[] deviceTypes = {0, 1, 0}; // 0-手机, 1-电脑
private int[] signalStrength = {3, 2, 1};
private int[] downloadRates = {50, 50, 0};
private int[] uploadRates = {25, 25, 0};
public ClientListAdapter(int itemCount, Context context, boolean isOnlineAdapter) {
this.itemCount = itemCount;
this.context = context;
this.isOnlineAdapter = isOnlineAdapter;
this.context = context;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return TPTwoLineItemViewHolder.create(parent);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
TPTwoLineItemView lineItem = (TPTwoLineItemView) holder.itemView;
// 直接使用数组中的模拟数据
String deviceName = deviceNames[position % deviceNames.length];
int deviceType = deviceTypes[position % deviceTypes.length];
int signal = signalStrength[position % signalStrength.length];
int downloadRate = downloadRates[position % downloadRates.length];
int uploadRate = uploadRates[position % uploadRates.length];
// 根据adapter类型决定status
int status = isOnlineAdapter ? 0 : 1; // 0-在线, 1-离线
// 设置设备类型图标
// DEVICE_TYPE_MOBILE_PHONE = 0, DEVICE_TYPE_DESKTOP = 1
if (deviceType == 1) { // DEVICE_TYPE_DESKTOP
lineItem.setStartIcon(R.mipmap.icon_laptop);
} else { // DEVICE_TYPE_MOBILE_PHONE
lineItem.setStartIcon(R.mipmap.icon_games);
}
// 设置图标尺寸
ViewGroup.LayoutParams layoutParams = lineItem.getStartIcon().getLayoutParams();
int iconSize = (int) context.getResources().getDimension(com.tplink.design.R.dimen.tpds_all_dp_40);
layoutParams.width = iconSize;
layoutParams.height = iconSize;
lineItem.getStartIcon().setLayoutParams(layoutParams);
lineItem.setTitleText(deviceName);
lineItem.showDivider(true);
if (status == 0) { // 在线设备
lineItem.setEndIcon(getMyEndIcon(signal));
setItemContentOnline(uploadRate, downloadRate, lineItem);
} else { // 离线设备
lineItem.setEndIcon(R.drawable.toolbar_icon_next);
setItemContentOffline(System.currentTimeMillis() - 24 * 60 * 60 * 1000, lineItem); // 一天前
}
// 设置长按事件
switch (status) {
case 0:
lineItem.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new TPPopupMenu(lineItem.getContext(), v, R.menu.clients_online_menu)
.setIconEnable(true)
.show();
return true;
}
});
break;
case 1:
lineItem.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new TPPopupMenu(lineItem.getContext(), v, R.menu.clients_offline_menu)
.setIconEnable(true)
.show();
return true;
}
});
break;
}
}
@Override
public int getItemCount() {
return itemCount;
}
// 设置在线设备content部分的TextView为 icon+text+icon+text的形式
private void setItemContentOnline(int uploadRate, int downloadRate, TPTwoLineItemView lineItem) {
TextView textView = lineItem.getContent();
android.graphics.Paint.FontMetrics fm = textView.getPaint().getFontMetrics();
float textHeight = fm.descent - fm.ascent;
String downloadText = " " + downloadRate + "KB/s";
String spaceText = " ";
String uploadText = " " + uploadRate + "KB/s";
SpannableString spannable = new SpannableString(downloadText + spaceText + uploadText);
Drawable uploadIconDrawable = ContextCompat.getDrawable(context, R.drawable.icon_upload_no_background);
Drawable downloadIconDrawable = ContextCompat.getDrawable(context, R.drawable.icon_download);
if (uploadIconDrawable != null && downloadIconDrawable != null) {
float iconAspectRatio = (float) uploadIconDrawable.getIntrinsicWidth() / uploadIconDrawable.getIntrinsicHeight();
int scaleWidth = (int) (textHeight * iconAspectRatio);
downloadIconDrawable.setBounds(0, 0, scaleWidth, (int) textHeight);
uploadIconDrawable.setBounds(0, 0, scaleWidth, (int) textHeight);
ImageSpan uploadIconSpan = new ImageSpan(uploadIconDrawable, ImageSpan.ALIGN_BOTTOM);
ImageSpan downloadIconSpan = new ImageSpan(downloadIconDrawable, ImageSpan.ALIGN_BOTTOM);
spannable.setSpan(downloadIconSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(
uploadIconSpan,
downloadText.length() + spaceText.length(),
downloadText.length() + spaceText.length() + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
}
textView.setText(spannable);
lineItem.getContent().setVisibility(View.VISIBLE);
}
// 设置离线设备content部分的TextView为上次登录时间
@SuppressLint("SimpleDateFormat")
private void setItemContentOffline(long lastOnlineTime, TPTwoLineItemView lineItem) {
SimpleDateFormat timeFormat = new SimpleDateFormat(context.getString(R.string.clients_time_format_pattern));
String timeString = timeFormat.format(new Date(lastOnlineTime));
String contentText = context.getString(R.string.clients_hint_current_online_time, timeString);
lineItem.setContentText(contentText);
}
// 设置endIcon为 signal icon + next icon的形式
private LayerDrawable getMyEndIcon(int strength) {
Drawable leftIcon;
switch (strength) {
case 1:
leftIcon = ContextCompat.getDrawable(context, R.drawable.icon_wifi_strength_1);
break;
case 2:
leftIcon = ContextCompat.getDrawable(context, R.drawable.icon_wifi_strength_2);
break;
case 3:
leftIcon = ContextCompat.getDrawable(context, R.drawable.icon_wifi_strength_3);
break;
default:
leftIcon = ContextCompat.getDrawable(context, R.drawable.icon_wifi_strength_3);
break;
}
Drawable rightIcon = ContextCompat.getDrawable(context, R.drawable.toolbar_icon_next);
Drawable[] layers = {leftIcon, rightIcon};
LayerDrawable layerDrawable = new LayerDrawable(layers);
int iconSize = (int) context.getResources().getDimension(com.tplink.design.R.dimen.tpds_all_dp_20);
int spacing = (int) context.getResources().getDimension(com.tplink.design.R.dimen.tpds_all_dp_20);
layerDrawable.setLayerSize(0, iconSize, iconSize);
layerDrawable.setLayerGravity(0, Gravity.CENTER_HORIZONTAL);
layerDrawable.setLayerGravity(1, Gravity.CENTER_HORIZONTAL);
layerDrawable.setLayerInset(0, -spacing, 0, 0, 0);
layerDrawable.setLayerInset(1, 2 * spacing, 0, 0, 0);
return layerDrawable;
}
}
package com.tplink.trainingapp.clients.adapter;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.tplink.design.list.TPTwoLineItemView;
import com.tplink.design.list.TPTwoLineItemViewHolder;
import com.tplink.design.menu.TPPopupMenu;
import com.tplink.trainingapp.R;
import com.tplink.trainingapp.clients.bean.ClientInfo;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class ClientListAdapterNormal extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<ClientInfo> clientList;
private Context context;
public ClientListAdapterNormal(List<ClientInfo> list, Context context) {
this.clientList = new ArrayList<>();
this.clientList.addAll(list);
this.context = context;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return TPTwoLineItemViewHolder.create(parent);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
TPTwoLineItemView lineItem = (TPTwoLineItemView) holder.itemView;
ClientInfo clientInfo = clientList.get(position);
// 设置设备类型图标
if (clientInfo.getDeviceType() == ClientInfo.DEVICE_TYPE_DESKTOP) {
lineItem.setStartIcon(R.mipmap.icon_laptop);
} else {
lineItem.setStartIcon(R.mipmap.icon_games);
}
// 设置图标尺寸
ViewGroup.LayoutParams layoutParams = lineItem.getStartIcon().getLayoutParams();
int iconSize = (int) context.getResources().getDimension(com.tplink.design.R.dimen.tpds_all_dp_40);
layoutParams.width = iconSize;
layoutParams.height = iconSize;
lineItem.getStartIcon().setLayoutParams(layoutParams);
lineItem.setTitleText(clientInfo.getDeviceName());
lineItem.showDivider(true);
if (clientInfo.getStatus() == 0) {
// 在线设备
lineItem.setEndIcon(getMyEndIcon(clientInfo.getSignalStrength()));
setItemContentOnline(
clientInfo.getUploadRate(),
clientInfo.getDownloadRate(),
lineItem
);
} else {
// 离线设备
lineItem.setEndIcon(R.drawable.toolbar_icon_next);
setItemContentOffline(clientInfo.getLastOnlineTime(), lineItem);
}
// 设置长按事件
switch (clientInfo.getStatus()) {
case 0:
lineItem.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new TPPopupMenu(lineItem.getContext(), v, R.menu.clients_online_menu)
.setIconEnable(true)
.show();
return true;
}
});
break;
case 1:
lineItem.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new TPPopupMenu(lineItem.getContext(), v, R.menu.clients_offline_menu)
.setIconEnable(true)
.show();
return true;
}
});
break;
}
}
@Override
public int getItemCount() {
return clientList.size();
}
// 设置在线设备content部分的TextView为 icon+text+icon+text的形式
private void setItemContentOnline(int uploadRate, int downloadRate, TPTwoLineItemView lineItem) {
TextView textView = lineItem.getContent();
android.graphics.Paint.FontMetrics fm = textView.getPaint().getFontMetrics();
float textHeight = fm.descent - fm.ascent;
String downloadText = " " + downloadRate + "KB/s";
String spaceText = " ";
String uploadText = " " + uploadRate + "KB/s";
SpannableString spannable = new SpannableString(downloadText + spaceText + uploadText);
Drawable uploadIconDrawable = ContextCompat.getDrawable(context, R.drawable.icon_upload_no_background);
Drawable downloadIconDrawable = ContextCompat.getDrawable(context, R.drawable.icon_download);
if (uploadIconDrawable != null && downloadIconDrawable != null) {
float iconAspectRatio = (float) uploadIconDrawable.getIntrinsicWidth() / uploadIconDrawable.getIntrinsicHeight();
int scaleWidth = (int) (textHeight * iconAspectRatio);
downloadIconDrawable.setBounds(0, 0, scaleWidth, (int) textHeight);
uploadIconDrawable.setBounds(0, 0, scaleWidth, (int) textHeight);
ImageSpan uploadIconSpan = new ImageSpan(uploadIconDrawable, ImageSpan.ALIGN_BOTTOM);
ImageSpan downloadIconSpan = new ImageSpan(downloadIconDrawable, ImageSpan.ALIGN_BOTTOM);
spannable.setSpan(downloadIconSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(
uploadIconSpan,
downloadText.length() + spaceText.length(),
downloadText.length() + spaceText.length() + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
}
textView.setText(spannable);
lineItem.getContent().setVisibility(View.VISIBLE);
}
// 设置离线设备content部分的TextView为上次登录时间
@SuppressLint("SimpleDateFormat")
private void setItemContentOffline(long lastOnlineTime, TPTwoLineItemView lineItem) {
SimpleDateFormat timeFormat = new SimpleDateFormat(context.getString(R.string.clients_time_format_pattern));
String timeString = timeFormat.format(new Date(lastOnlineTime));
String contentText = context.getString(R.string.clients_hint_current_online_time, timeString);
lineItem.setContentText(contentText);
}
// 设置endIcon为 signal icon + next icon的形式
private LayerDrawable getMyEndIcon(int strength) {
Drawable leftIcon;
switch (strength) {
case 1:
leftIcon = ContextCompat.getDrawable(context, R.drawable.icon_wifi_strength_1);
break;
case 2:
leftIcon = ContextCompat.getDrawable(context, R.drawable.icon_wifi_strength_2);
break;
case 3:
leftIcon = ContextCompat.getDrawable(context, R.drawable.icon_wifi_strength_3);
break;
default:
leftIcon = ContextCompat.getDrawable(context, R.drawable.icon_wifi_strength_3);
break;
}
Drawable rightIcon = ContextCompat.getDrawable(context, R.drawable.toolbar_icon_next);
Drawable[] layers = {leftIcon, rightIcon};
LayerDrawable layerDrawable = new LayerDrawable(layers);
int iconSize = (int) context.getResources().getDimension(com.tplink.design.R.dimen.tpds_all_dp_20);
int spacing = (int) context.getResources().getDimension(com.tplink.design.R.dimen.tpds_all_dp_20);
layerDrawable.setLayerSize(0, iconSize, iconSize);
layerDrawable.setLayerGravity(0, Gravity.CENTER_HORIZONTAL);
layerDrawable.setLayerGravity(1, Gravity.CENTER_HORIZONTAL);
layerDrawable.setLayerInset(0, -spacing, 0, 0, 0);
layerDrawable.setLayerInset(1, 2 * spacing, 0, 0, 0);
return layerDrawable;
}
}
package com.tplink.trainingapp.clients.view;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import com.tplink.apps.architecture.BaseMvvmFragment;
import com.tplink.trainingapp.clients.adapter.ClientListAdapterNormal;
import com.tplink.trainingapp.clients.viewmodel.ClientViewModel;
import com.tplink.trainingapp.databinding.FragmentClientsGuestBinding;
public class ClientGuestFragment extends BaseMvvmFragment<FragmentClientsGuestBinding> {
private ClientViewModel viewModel;
private ClientListAdapterNormal adapter;
@NonNull
@Override
protected FragmentClientsGuestBinding bindView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return FragmentClientsGuestBinding.inflate(inflater, container, false);
}
@Override
protected void subscribeViewModel(@Nullable Bundle savedInstanceState) {
viewModel = new ViewModelProvider(requireActivity()).get(ClientViewModel.class);
initView();
}
private void initView() {
adapter = new ClientListAdapterNormal(
viewModel.getGuestClients(),
requireActivity().getBaseContext()
);
viewBinding.rvOnline.setAdapter(adapter);
}
}
package com.tplink.trainingapp.clients.view;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import com.tplink.apps.architecture.BaseMvvmFragment;
import com.tplink.design.menu.TPPopupMenu;
import com.tplink.trainingapp.R;
import com.tplink.trainingapp.clients.adapter.ClientListAdapterNormal;
import com.tplink.trainingapp.clients.viewmodel.ClientViewModel;
import com.tplink.trainingapp.databinding.FragmentClientsMainBinding;
public class ClientMainFragment extends BaseMvvmFragment<FragmentClientsMainBinding> {
private ClientViewModel viewModel;
private ClientListAdapterNormal onlineAdapter;
private ClientListAdapterNormal offlineAdapter;
@Override
protected FragmentClientsMainBinding bindView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return FragmentClientsMainBinding.inflate(inflater, container, false);
}
@Override
protected void subscribeViewModel(@Nullable Bundle savedInstanceState) {
viewModel = new ViewModelProvider(requireActivity()).get(ClientViewModel.class);
initView();
}
private void initView() {
onlineAdapter = new ClientListAdapterNormal(
viewModel.getMainClientsOnline(),
requireActivity().getBaseContext()
);
viewBinding.rvOnline.setAdapter(onlineAdapter);
offlineAdapter = new ClientListAdapterNormal(
viewModel.getMainClientsOffline(),
requireActivity().getBaseContext()
);
viewBinding.rvOffline.setAdapter(offlineAdapter);
viewBinding.btnOffline.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new TPPopupMenu(requireContext(), v, R.menu.clients_online_menu)
.setIconEnable(true)
.show();
}
});
}
}
// 原来的按钮点击事件现在变得非常简洁
viewBinding.tvRegion.setOnClickListener(v -> showCountrySelectionModal());
private void showCountrySelectionModal() {
CountrySelectionFragment fragment = CountrySelectionFragment.newInstance();
fragment.setCountryViewModel(countryViewModel);
fragment.setOnCountrySelectedListener(countryName -> {
// 处理国家选择结果
// countryViewModel.selectCountry(countryName); // 这个在Fragment内部已经处理了
// 可以在这里添加其他需要的逻辑,比如更新UI
updateRegionDisplay();
});
fragment.show(getSupportFragmentManager(), "country_selection");
}
private void updateRegionDisplay() {
// 更新显示选中的地区
String selectedCountry = countryViewModel.getCurrentSelectedCountry();
if (selectedCountry != null) {
viewBinding.tvRegion.setText(selectedCountry);
}
}
public class CountrySelectionFragment extends TPModalBottomSheet {
private CountryViewModel countryViewModel;
private OnCountrySelectedListener listener;
// 回调接口
public interface OnCountrySelectedListener {
void onCountrySelected(String countryName);
}
public static CountrySelectionFragment newInstance() {
CountrySelectionFragment fragment = new CountrySelectionFragment();
return fragment;
}
public void setCountryViewModel(CountryViewModel viewModel) {
this.countryViewModel = viewModel;
}
public void setOnCountrySelectedListener(OnCountrySelectedListener listener) {
this.listener = listener;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 不直接设置属性,通过重写方法来实现
}
// 重写初始化TopBar的方法
@Override
public void initTopBar() {
super.initTopBar();
// 在这里设置TopBar相关属性
if (topBar != null) {
topBar.setTitle("Region");
topBar.setEndOptionText("Done");
}
// 设置分隔线不显示
if (topBarDivider != null) {
topBarDivider.setVisibility(View.GONE);
}
}
@Override
public void onContentViewCreated(View view, Bundle savedInstanceState) {
super.onContentViewCreated(view, savedInstanceState);
if (countryViewModel != null) {
setupCountrySelectionUI(view);
}
}
// 重写这个方法来指定布局ID
@Override
protected int getLayoutResId() {
return R.layout.fragment_region;
}
// 重写这个方法来指定屏幕类型
protected ScreenType getScreenType() {
return ScreenType.FULL_SCREEN;
}
private void setupCountrySelectionUI(View contentView) {
RecyclerView recyclerView = contentView.findViewById(R.id.recyclerView_countries);
CountryAdapter countryAdapter = new CountryAdapter(countryViewModel.getAllCountries());
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(countryAdapter);
// 设置当前选中的国家
String currentCountry = countryViewModel.getCurrentSelectedCountry();
if (currentCountry != null && !currentCountry.trim().isEmpty()) {
countryAdapter.setSelectedCountry(currentCountry);
}
countryAdapter.setOnCountryClickListener(new CountryAdapter.OnCountryClickListener() {
@Override
public void onCountryClick(String countryName, int position) {
countryViewModel.selectCountry(countryName);
// 通知外部监听器
if (listener != null) {
listener.onCountrySelected(countryName);
}
// 关闭对话框
dismiss();
}
});
// 观察过滤后的国家列表变化,实时更新RecyclerView
countryViewModel.filteredCountries.observe(this, countries -> {
countryAdapter.updateData(countries);
if(countries.size() == countryViewModel.getAllCountries().size()){
String selectedCountry = countryViewModel.getCurrentSelectedCountry();
if(selectedCountry != null && !selectedCountry.isEmpty()){
int selectedPosition = countryAdapter.getSelectedPosition();
if(selectedPosition >= 0){
recyclerView.post(() -> {
recyclerView.smoothScrollToPosition(selectedPosition);
});
}
}
}
});
countryViewModel.selectedCountry.observe(this, selectedCountry -> {
countryAdapter.setSelectedCountry(selectedCountry);
});
setupSearchView(contentView, countryAdapter);
}
/**
* 设置搜索功能
*/
private void setupSearchView(View contentView, CountryAdapter countryAdapter) {
TPSearchBar tpSearchBar = contentView.findViewById(R.id.tp_search);
// 创建搜索建议数据
ArrayList<String> searchData = new ArrayList<>(countryViewModel.getAllCountries());
// 创建搜索适配器
SearchViewBaseAdapter<String> searchAdapter = new SearchViewBaseAdapter<String>(
searchData,
new SearchViewBaseAdapter.OnBindDataListener<String>() {
@Override
public void onBindViewHolder(String model, SearchViewBaseViewHolder viewHolder, int type, int position) {
viewHolder.setText(R.id.tv_country_name, model);
}
@Override
public int getLayoutId(int type) {
return R.layout.item_country;
}
}
);
// 设置搜索结果点击事件
searchAdapter.setItemClickListener(new SearchViewBaseAdapter.OnItemClickListener<String>() {
@Override
public void onClick(View view, String data) {
// 通过ViewModel选择国家
countryViewModel.selectCountry(data);
countryAdapter.setSelectedCountry(data);
tpSearchBar.dismissSearchView();
countryViewModel.clearSearch();
// 通知外部监听器
if (listener != null) {
listener.onCountrySelected(data);
}
// 关闭对话框
dismiss();
}
});
// 设置搜索字符实时监听
tpSearchBar.setTextChangeListener(new TPMaterialSearchView.TextChangeListener() {
@Override
public void onTextChange(String searchText) {
countryViewModel.filterCountries(searchText);
// 过滤搜索建议
if (searchText == null || searchText.trim().isEmpty()) {
searchAdapter.updateData(new ArrayList<>(countryViewModel.getAllCountries()));
} else {
ArrayList<String> filteredList = getFilteredCountries(searchText);
searchAdapter.updateData(filteredList);
}
}
});
tpSearchBar.setManager(getChildFragmentManager());
tpSearchBar.setSearchViewAdapter(searchAdapter);
tpSearchBar.setOnQueryTextListener(new TPMaterialSearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
}
private ArrayList<String> getFilteredCountries(String searchText) {
ArrayList<String> filteredList = new ArrayList<>();
if (searchText != null && !searchText.trim().isEmpty()) {
String searchLower = searchText.toLowerCase().trim();
for (String country : countryViewModel.getAllCountries()) {
if (country != null && country.toLowerCase().contains(searchLower)) {
filteredList.add(country);
}
}
} else {
filteredList.addAll(countryViewModel.getAllCountries());
}
return filteredList;
}
}
public class CountrySelectionFragment extends TPModalBottomSheet {
private CountryViewModel countryViewModel;
private OnCountrySelectedListener listener;
// 回调接口
public interface OnCountrySelectedListener {
void onCountrySelected(String countryName);
}
public static CountrySelectionFragment newInstance() {
CountrySelectionFragment fragment = new CountrySelectionFragment();
return fragment;
}
public void setCountryViewModel(CountryViewModel viewModel) {
this.countryViewModel = viewModel;
}
public void setOnCountrySelectedListener(OnCountrySelectedListener listener) {
this.listener = listener;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置模态框属性
screenType = ScreenType.FULL_SCREEN;
dividerEnable = false;
topBarTitleText = "Region";
topBarEndText = "Done";
contentLayoutId = R.layout.fragment_region;
}
@Override
public void onContentViewCreated(View view, Bundle savedInstanceState) {
super.onContentViewCreated(view, savedInstanceState);
if (countryViewModel != null) {
setupCountrySelectionUI(view);
}
}
private void setupCountrySelectionUI(View contentView) {
RecyclerView recyclerView = contentView.findViewById(R.id.recyclerView_countries);
CountryAdapter countryAdapter = new CountryAdapter(countryViewModel.getAllCountries());
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(countryAdapter);
// 设置当前选中的国家
String currentCountry = countryViewModel.getCurrentSelectedCountry();
if (currentCountry != null && !currentCountry.trim().isEmpty()) {
countryAdapter.setSelectedCountry(currentCountry);
}
countryAdapter.setOnCountryClickListener(new CountryAdapter.OnCountryClickListener() {
@Override
public void onCountryClick(String countryName, int position) {
countryViewModel.selectCountry(countryName);
// 通知外部监听器
if (listener != null) {
listener.onCountrySelected(countryName);
}
// 关闭对话框
dismiss();
}
});
// 观察过滤后的国家列表变化,实时更新RecyclerView
countryViewModel.filteredCountries.observe(this, countries -> {
countryAdapter.updateData(countries);
if(countries.size() == countryViewModel.getAllCountries().size()){
String selectedCountry = countryViewModel.getCurrentSelectedCountry();
if(selectedCountry != null && !selectedCountry.isEmpty()){
int selectedPosition = countryAdapter.getSelectedPosition();
if(selectedPosition >= 0){
recyclerView.post(() -> {
recyclerView.smoothScrollToPosition(selectedPosition);
});
}
}
}
});
countryViewModel.selectedCountry.observe(this, selectedCountry -> {
countryAdapter.setSelectedCountry(selectedCountry);
});
setupSearchView(contentView, countryAdapter);
}
/**
* 设置搜索功能
*/
private void setupSearchView(View contentView, CountryAdapter countryAdapter) {
TPSearchBar tpSearchBar = contentView.findViewById(R.id.tp_search);
// 创建搜索建议数据
ArrayList<String> searchData = new ArrayList<>(countryViewModel.getAllCountries());
// 创建搜索适配器
SearchViewBaseAdapter<String> searchAdapter = new SearchViewBaseAdapter<String>(
searchData,
new SearchViewBaseAdapter.OnBindDataListener<String>() {
@Override
public void onBindViewHolder(String model, SearchViewBaseViewHolder viewHolder, int type, int position) {
viewHolder.setText(R.id.tv_country_name, model);
}
@Override
public int getLayoutId(int type) {
return R.layout.item_country;
}
}
);
// 设置搜索结果点击事件
searchAdapter.setItemClickListener(new SearchViewBaseAdapter.OnItemClickListener<String>() {
@Override
public void onClick(View view, String data) {
// 通过ViewModel选择国家
countryViewModel.selectCountry(data);
countryAdapter.setSelectedCountry(data);
tpSearchBar.dismissSearchView();
countryViewModel.clearSearch();
// 通知外部监听器
if (listener != null) {
listener.onCountrySelected(data);
}
// 关闭对话框
dismiss();
}
});
// 设置搜索字符实时监听
tpSearchBar.setTextChangeListener(new TPMaterialSearchView.TextChangeListener() {
@Override
public void onTextChange(String searchText) {
countryViewModel.filterCountries(searchText);
// 过滤搜索建议
if (searchText == null || searchText.trim().isEmpty()) {
searchAdapter.updateData(new ArrayList<>(countryViewModel.getAllCountries()));
} else {
ArrayList<String> filteredList = getFilteredCountries(searchText);
searchAdapter.updateData(filteredList);
}
}
});
tpSearchBar.setManager(getChildFragmentManager());
tpSearchBar.setSearchViewAdapter(searchAdapter);
tpSearchBar.setOnQueryTextListener(new TPMaterialSearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
}
private ArrayList<String> getFilteredCountries(String searchText) {
ArrayList<String> filteredList = new ArrayList<>();
if (searchText != null && !searchText.trim().isEmpty()) {
String searchLower = searchText.toLowerCase().trim();
for (String country : countryViewModel.getAllCountries()) {
if (country != null && country.toLowerCase().contains(searchLower)) {
filteredList.add(country);
}
}
} else {
filteredList.addAll(countryViewModel.getAllCountries());
}
return filteredList;
}
}
主要变化:
-
属性设置方式 - 直接给protected字段赋值,而不是调用方法:
screenType = ScreenType.FULL_SCREEN; // 而不是setScreenType() dividerEnable = false; // 而不是setDividerEnable() topBarTitleText = "Region"; // 而不是setTitle() -
布局设置 - 使用
contentLayoutId字段:contentLayoutId = R.layout.fragment_region; -
UI初始化 - 重写
onContentViewCreated方法,这是TPModalBottomSheet的标准生命周期方法