我正在尝试创建一个带有产品列表和产品主详细信息的简单应用程序。 至于我最初的尝试,我使用BottomNavigationView创建了该应用程序,在该应用程序的底部有小图标,您可以通过单击其中一个片段来切换片段。我目前在bottomNavigationBar上有4个图标,这是4个图标:
这4个片段是在我的HomeActivity中切换的,这就是我切换它们的方式:
HomeActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
bottomNavbar = findViewById(R.id.nav_view);
bottomNavbar.setOnNavigationItemSelectedListener(navListener);
homeContainer = findViewById(R.id.homeContainer);
createSnackbar(homeContainer);
viewModel = new HomeViewModel();
viewModel.getCartCounterLiveData().observe(this, CartCounterObserver);
createBadges(bottomNavbar);
}
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
BaseRTFFragment selectedFragment = null;
String stackName;
switch(item.getItemId()) {
case R.id.nav_home:
selectedFragment = new ProductsFragment();
break;
case R.id.nav_favorites:
selectedFragment = new FavoritesFragment();
break;
case R.id.nav_profile:
selectedFragment = new ProfileFragment();
break;
case R.id.nav_cart:
selectedFragment = new CartFragment();
break;
}
navigateToFragment(selectedFragment);
return true;
}
};
private void navigateToFragment(BaseRTFFragment selectedFragment) {
FragmentTransaction fTrans = getSupportFragmentManager().beginTransaction();
// fTrans.addToBackStack(selectedFragment.getFragmentName());
fTrans.replace(R.id.nav_host_fragment, selectedFragment).commit();
}
因此,这只是对replace()的简单调用。此时工作正常,片段之间切换时没有黑屏
顺便说一下,ProductsFragment具有searchText,类别过滤器按钮和分页的recyclerView来显示产品列表。请参见下面的代码:
ProductsFragment.java
public class ProductsFragment extends BaseRTFFragment<FragmentProductsBinding>
implements Observer<PagedList<Product>>, ProductsAdapter.OnProductClickListener, CategoryAdapter.OnCategoryClickListener {
ProductsViewModel viewModel;
ProductsAdapter productsAdapter;
int selectedCategory;
String currentSearchText;
ProductsEventsListener listener;
private CategoryAdapter categoryAdapter;
private String fragmentName = "Products";
@Override
protected int getFragmentLayout() {
return R.layout.fragment_products;
}
@Override
public String getFragmentName() { return fragmentName; }
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewModel = new ProductsViewModel();
initProductsAdapter();
initCategoryAdapter();
initializeSearch();
loadProducts();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
listener = (ProductsEventsListener) context;
} catch (ClassCastException castException) {
throw new Error("The activity does not implement the listener");
}
}
private void initProductsAdapter() {
productsAdapter = new ProductsAdapter(this);
dataBinding.productsRecyclerView.setAdapter(productsAdapter);
}
private void initCategoryAdapter() {
Query cQuery = initCategoryQuery();
cQuery.get().addOnCompleteListener(categoryListener);
}
private OnCompleteListener<QuerySnapshot> categoryListener = new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()) {
List<Category> categories = task.getResult().toObjects(Category.class);
categoryAdapter = getCategoryAdapter(categories);
dataBinding.categoryRecyclerView.setAdapter(categoryAdapter);
}
}
};
private CategoryAdapter getCategoryAdapter(List<Category> categories) {
return new CategoryAdapter(categories, this);
}
private Query initCategoryQuery() {
FirebaseFirestore mFirestore = FirebaseFirestore.getInstance();
return mFirestore.collection("categories")
.orderBy("name", Query.Direction.ASCENDING);
}
private void loadProducts() {
viewModel.pagedListLiveData.observe(getViewLifecycleOwner(), this);
}
private void reloadProducts() {
viewModel.replaceSubscription(this, null, 0);
loadProducts();
}
private void loadSearchedProducts(String searchText, int category) {
viewModel.replaceSubscription(this, searchText, category);
loadProducts();
}
@Override
public void onChanged(PagedList<Product> products) {
productsAdapter.submitList(products);
hideProgressBar();
// toggleEmptyLayout(products.size());
}
private void toggleEmptyLayout(int count) {
if(count > 0) {
dataBinding.productsRecyclerView.setVisibility(View.VISIBLE);
dataBinding.emptyResultLayout.setVisibility(View.GONE);
} else {
dataBinding.productsRecyclerView.setVisibility(View.GONE);
dataBinding.emptyResultLayout.setVisibility(View.VISIBLE);
}
}
private void hideProgressBar() {
dataBinding.progressBar.setVisibility(View.GONE);
}
public int getSelectedCategory() {
return selectedCategory;
}
@Override
public void onProductClick(Product product) {
displayProductName(product.getName() + " has been clicked!");
listener.OnProductClick(product);
}
@Override
public void onAddProductToCart(Product product) {
// displayProductName(product.getName() + " has been added to cart");
listener.OnAddProductToCart(product);
}
@Override
public void onFavoriteProduct(Product product) {
listener.OnFavoriteProduct(product);
}
private void displayProductName(String name) {
Toast.makeText(getActivity(), name, Toast.LENGTH_SHORT).show();
}
private void initializeSearch() {
dataBinding.searchInput.addTextChangedListener(searchTextWatcher);
}
private TextWatcher searchTextWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable searchText) {
String sText = searchText.toString().toLowerCase();;
if (sText != currentSearchText) {
currentSearchText = sText;
loadSearchedProducts(currentSearchText, selectedCategory);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
};
@Override
public void onCategoryClick(int selectedCategoryId) {
selectedCategory = selectedCategoryId;
loadSearchedProducts(currentSearchText, selectedCategory);
}
}
我所有的Fragments都继承了一个自定义基本片段,该片段仅从android Fragment继承,请参见下面的代码:
BaseRTFFragment.java
public abstract class BaseRTFFragment<T extends ViewDataBinding> extends Fragment {
protected T dataBinding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle bundle) {
dataBinding = DataBindingUtil.inflate(inflater, getFragmentLayout(), null, false);
return dataBinding.getRoot();
}
protected abstract int getFragmentLayout();
public abstract String getFragmentName();
@Override
public void onDestroyView() {
super.onDestroyView();
dataBinding = null;
}
}
现在一切都很好,现在该添加产品详细信息页面了。 为此,我创建了一个新的ProductFragment(注意名称中没有's')
ProductFragment.java
public class ProductFragment extends BaseRTFFragment<FragmentProductBinding> implements Observer<Product> {
ProductViewModel viewModel;
ProductEventsListener listener;
private String fragmentName = "Product";
@Override
protected int getFragmentLayout() {
return R.layout.fragment_product;
}
@Override
public String getFragmentName() { return fragmentName; }
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle bundle) {
int productId = getArguments().getInt("productId");
viewModel = new ProductViewModel(productId);
viewModel.getProduct(productId).observe(getViewLifecycleOwner(), this);
return super.onCreateView(inflater, container, bundle);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
listener = (ProductEventsListener) context;
} catch (ClassCastException castException) {
throw new Error("The activity does not implement the listener");
}
}
@Override
public void onChanged(Product product) {
dataBinding.productTitle.setText(product.getName());
}
}
有关此片段的布局,请参见下面的代码:
fragment_product.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/productFragmentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/productAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/productCollapseToolbar"
android:layout_width="match_parent"
android:layout_height="256dp"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:titleEnabled="false">
<ImageView
android:id="@+id/htab_header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/ic_default_product"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.3"
android:background="@android:color/black"
android:fitsSystemWindows="true"/>
<ImageButton
android:id="@+id/backBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:tint="@color/colorSecondary"
android:padding="@dimen/btn_padding"
android:layout_margin="@dimen/btn_padding"
android:onClick="OnNavigateBack"
android:src="@drawable/ic_previous"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/default_page_padding"
android:orientation="vertical">
<TextView
android:id="@+id/productTitle"
style="@style/ProductTitle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/btn_padding"
android:text="Growers Mix"/>
<TextView
android:id="@+id/productDescription"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Test"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
请注意ImageButton,我已经在HomeActivity.java中声明了OnNavigateBack方法,因为在ProductFragment.java上声明它会导致一些错误,表明它找不到类似的方法,因此我在家庭活动。看起来是这样的:
HomeActivity.java:OnNavigateBack
@Override
public void OnNavigateBack() {
navigateToFragment(new ProductsFragment());
}
private void navigateToFragment(BaseRTFFragment selectedFragment) {
FragmentTransaction fTrans = getSupportFragmentManager().beginTransaction();
// fTrans.addToBackStack(selectedFragment.getFragmentName());
fTrans.replace(R.id.nav_host_fragment, selectedFragment).commit();
}
@Override
public void OnProductClick(Product product) {
// displayProductName(product.getName() + " should be viewed in a separate fragment");
Bundle bundle = new Bundle();
bundle.putInt("productId", product.getId());
ProductFragment productFragment = new ProductFragment();
productFragment.setArguments(bundle);
navigateToFragment(productFragment);
}
它只是从前调用NavigationToFragment()方法。但是这一次,每次我单击ProductFragment中的“后退”按钮时,它都会呈现黑屏至少1秒钟,并加载产品列表。我不确定什么地方出了问题,因为我只是以与其他片段相同的方式加载片段。有什么我想念的吗?还是我的方法是错误的?我该怎么办?请帮忙。预先感谢。
答案 0 :(得分:0)
为此找到了一个解决方案,看来使用片段布局中的android:onClick属性,绑定无法正常运行。因此,我通过在后退按钮上设置onClickListener来绑定绑定点击事件的旧方法:
要做的事情:
ProductFragment.java
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
bindEvents();
}
private void bindEvents() {
dataBinding.backBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onNavigateBack();
}
});
}
我从现在开始不做任何事情:
fragment_product.xml
...
<ImageButton
....
android:id="@+id/backBtn"
android:onClick="onProductClick"
... />
...