У меня есть ViewPager 2 внутри plannerFragment, который вызывает 2 фрагмента: один (localeChoosingFragment) содержит recyclerview, позволяющий пользователю выбирать языковой стандарт, а другой — для выбора мест в этом языковом стандарте (localeExploringFragment). ViewModel (japanGuideViewModel) хранит данные (как MutableLiveData), включая int currentLocaleBeingViewed. Когда пользователь выбирает языковой стандарт, он обновляется, и наблюдатель в plannerFragment вызывает обновление одной из вкладок в PlannerFragment именем этого языкового стандарта. При нажатии на эту вкладку загружается localeExploringFragment для этой локали.
Когда срабатывает наблюдатель в plannerFragment, вкладка обновляется. Это приводит к тому, что представление recyclerview в localeChoosingFragment сбрасывается в первую позицию. В качестве обходного пути я попытался использовать обработчик для автоматической прокрутки представления recyclerview в нужное место (согласно ViewModel), но я смущен и обеспокоен тем, почему это происходит. Перед использованием ViewPager2 я добавил оба (localeChoosingFragment и localeExploringFragment) в макет кадра вручную и попробовал показать/скрыть и прикрепить/отсоединить, но возникла та же проблема (сброс представления recyclerview в первую позицию).
Кто-нибудь знает, почему так может быть? Это кажется мелочью, но я обеспокоен тем, что происходит что-то, о чем я не знаю и о чем должен знать, особенно на этой ранней стадии проекта.
Recyclerview не воссоздается, и и notifyDataSet не изменился.
Этот ViewPager 2 на самом деле является частью фрагмента, выбранного из другого ViewPager 2, но я не думаю, что это вызывает проблему.Я приложу очищенную версию своего кода.
Вот планировщик:
public class LocaleChoosingFragment extends Fragment {
JapanGuideViewModel japanGuideViewModel;
Context mContext;
View localeChoosingFragmentView;
public static final String TAG = "JapanGuideTAG";
RecyclerView localeChoosingRecyclerView;
LinearLayoutManager recyclerViewLayoutManager;
LocaleChoosingRecyclerViewAdaptor localeChoosingAdaptor;
SnapHelperOneByOne SnapHelper;
public LocaleChoosingFragment() {
Log.d(TAG, "EMPTY constructor called for localeChoosingFragment");
}
public LocaleChoosingFragment(Context mContext, JapanGuideViewModel japanGuideViewModel) {
this.japanGuideViewModel = japanGuideViewModel;
this.mContext = mContext;
Log.d(TAG, "constructor called for localeChoosingFragment");
Toast.makeText(mContext, "Creating a new localeChoosingFragment", Toast.LENGTH_SHORT).show();
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate in localeChoosingFragment");
super.onCreate(savedInstanceState);
Log.d(TAG, "creating a NEW LOCALECHOOSING RECYCLERVIEW");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.d(TAG, "onCreateView called in LocalChoosingFragment");
localeChoosingFragmentView = inflater.inflate(R.layout.fragment_locale_choosing, container, false);
localeChoosingRecyclerView = localeChoosingFragmentView.findViewById(R.id.localeChoosingRecyclerView);
return localeChoosingFragmentView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, "onviewcreated in locale choosing fragment.");
localeChoosingAdaptor = new LocaleChoosingRecyclerViewAdaptor(mContext, japanGuideViewModel);
SnapHelper = new SnapHelperOneByOne();
recyclerViewLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false);
localeChoosingRecyclerView.setLayoutManager(recyclerViewLayoutManager);
localeChoosingRecyclerView.setAdapter(localeChoosingAdaptor);
SnapHelper.attachToRecyclerView(localeChoosingRecyclerView);
// localeChoosingRecyclerView.scrollToPosition(japanGuideViewModel.getCurrentLocaleBeingViewed().getValue());
}
public class LocaleChoosingRecyclerViewAdaptor extends RecyclerView.Adapter {
Context mContext;
JapanGuideViewModel japanGuideViewModel;
Button exploreNowButton;
Button wontGoHereButton;
TextView localeNameTextView;
TextView localeDescriptionTextView;
ImageView localePhotoImageView;
TextView localePhotoCaptionTextView;
public LocaleChoosingRecyclerViewAdaptor() {
Log.d(TAG, "localeChoosingAdaptor created with empty constructor");
}
public LocaleChoosingRecyclerViewAdaptor(Context mContext, JapanGuideViewModel japanGuideViewModel) {
this.mContext = mContext;
this.japanGuideViewModel = japanGuideViewModel;
Log.d(TAG, "localeChoosingAdaptor created with full constructor");
}
@NonNull
@Override
public LocaleChoosingAdaptorHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Log.d(TAG, "oncreateviewholder in localechoosingfragment");
View view = LayoutInflater.from(mContext).inflate(R.layout.locale_recyclerview_holder, parent, false);
return new LocaleChoosingAdaptorHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder called in localeChoosingFragment. The position is " + position + " and the total size is " + getItemCount());
localeNameTextView = holder.itemView.findViewById(R.id.localeRecyclerviewHolderHeadingTextview);
localeNameTextView.setText(japanGuideViewModel.getLocalesDetailsArray().getValue().get(position).getLocaleName());
localeDescriptionTextView = holder.itemView.findViewById(R.id.localeRecyclerviewHolderDescriptionTextView);
if (japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getLocaleDescription() != null) {
localeDescriptionTextView.setText(japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getLocaleDescription());
}
localePhotoImageView = holder.itemView.findViewById(R.id.localeRecyclerviewHolderImageView);
if ((japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getPhotoSet().size() != 0)) {
if ((japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getPhotoSet().get(0).getURL() != null) && (!(japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getPhotoSet().get(0).getURL().equals("")))) {
Glide.with(mContext).load(japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getPhotoSet().get(0).getURL()).into(localePhotoImageView);
}
localePhotoCaptionTextView = holder.itemView.findViewById(R.id.localeRecyclerviewHolderPhotoCaptionTextView);
if ((japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getPhotoSet().get(0).getCaption() != null) && (japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getPhotoSet().get(0).getCaption() != "")) {
localePhotoCaptionTextView.setText(japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getPhotoSet().get(0).getCaption());
}
}
exploreNowButton = holder.itemView.findViewById(R.id.LocaleRecyclerviewHolderExploreNowButton);
wontGoHereButton = holder.itemView.findViewById(R.id.LocaleRecyclerviewHolderWontGoHereButton);
exploreNowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, "Explore now button clicked. Setting the locale to explore to " + japanGuideViewModel.getCurrentLocaleBeingViewed().getValue());
japanGuideViewModel.getCurrentLocaleBeingViewed().setValue(holder.getAdapterPosition());
}
});
} //bind
@Override
public int getItemCount() {
return japanGuideViewModel.getLocalesDetailsArray().getValue().size();
}
} //recyclerview adaptor
public class LocaleChoosingAdaptorHolder extends RecyclerView.ViewHolder {
TextView localeNameTextView;
TextView localeDescriptionTextView;
Button exploreNowButton;
Button wontGoHereButton;
public LocaleChoosingAdaptorHolder(@NonNull View itemView) {
super(itemView);
Log.d(TAG, "localechoosing recyclerview holder constructor called");
localeNameTextView = itemView.findViewById(R.id.localeRecyclerviewHolderHeadingTextview);
localeDescriptionTextView = itemView.findViewById(R.id.localeRecyclerviewHolderDescriptionTextView);
exploreNowButton = itemView.findViewById(R.id.LocaleRecyclerviewHolderExploreNowButton);
wontGoHereButton = itemView.findViewById(R.id.LocaleRecyclerviewHolderWontGoHereButton);
}
}
}
Я не ожидал, что RecyclerView в LocaleChoosingFragment вернется в первую позицию, когда наблюдатель в plannerFragment запускается наблюдателем в plannerFragment currentLocaleBeingViewed в Viewmodel. Все остальное работает как положено.
У меня есть ViewPager 2 внутри plannerFragment, который вызывает 2 фрагмента: один (localeChoosingFragment) содержит recyclerview, позволяющий пользователю выбирать языковой стандарт, а другой — для выбора мест в этом языковом стандарте (localeExploringFragment). ViewModel (japanGuideViewModel) хранит данные (как MutableLiveData), включая int currentLocaleBeingViewed. Когда пользователь выбирает языковой стандарт, он обновляется, и наблюдатель в plannerFragment вызывает обновление одной из вкладок в PlannerFragment именем этого языкового стандарта. При нажатии на эту вкладку загружается localeExploringFragment для этой локали. Когда срабатывает наблюдатель в plannerFragment, вкладка обновляется. Это приводит к тому, что представление recyclerview в localeChoosingFragment сбрасывается в первую позицию. В качестве обходного пути я попытался использовать обработчик для автоматической прокрутки представления recyclerview в нужное место (согласно ViewModel), но я смущен и обеспокоен тем, почему это происходит. Перед использованием ViewPager2 я добавил оба (localeChoosingFragment и localeExploringFragment) в макет кадра вручную и попробовал показать/скрыть и прикрепить/отсоединить, но возникла та же проблема (сброс представления recyclerview в первую позицию). Кто-нибудь знает, почему так может быть? Это кажется мелочью, но я обеспокоен тем, что происходит что-то, о чем я не знаю и о чем должен знать, особенно на этой ранней стадии проекта. Recyclerview не воссоздается, и и notifyDataSet не изменился. Этот ViewPager 2 на самом деле является частью фрагмента, выбранного из другого ViewPager 2, но я не думаю, что это вызывает проблему.Я приложу очищенную версию своего кода. Вот планировщик: [code] public class PlannerFragment extends Fragment {
TabLayoutMediator.TabConfigurationStrategy tabConfigurationStrategy = new TabLayoutMediator.TabConfigurationStrategy() { @Override public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
Log.d(TAG, "onConfigure in tabConfigurationStrategy");
Log.d(TAG, "attachingTabLayoutMediator"); new TabLayoutMediator(tabLayout, plannerFragmentViewPager2, tabConfigurationStrategy).attach();
Observer dataDownloadedObserver = new Observer() { @Override public void onChanged(Object o) {
if (japanGuideViewModel.getDataDownloaded().getValue() > 0) { Log.d(TAG, "onChanged called in data downloaded observer. Value is " + japanGuideViewModel.getDataDownloaded().getValue());
Observer localeToExploreChangedObserver = new Observer() { @Override public void onChanged(Object o) { Log.d(TAG, "localeChangedObserver in planner fragment"); TabLayout.Tab tab = tabLayout.getTabAt(1); if (tab != null) { Log.d(TAG, "the tab is" + tab.getPosition());
// THIS IS WHERE THE PROBLEM OCCURS. // If this line (setting the text) is removed, the recyclerview in // localeChoosingFragment does not reset to the first position. tab.setText(japanGuideViewModel.getLocaleNamesArray().getValue().get(japanGuideViewModel.getCurrentLocaleBeingViewed().getValue())); } } };
@NonNull @Override public Fragment createFragment(int position) { Log.d(TAG, "createFragment called in plannerFragment. Position is "); switch (position) { case 0:
Log.d(TAG, "planner fragment, case 0, localechoosingfragment");
LocaleChoosingFragment localeChoosingFragment = new LocaleChoosingFragment(mContext, japanGuideViewModel);
return localeChoosingFragment;
case 1:
Log.d("planner fragment localeExploringFragmentTAG", "case 1");
LocaleExploringFragment localeExploringFragment = new LocaleExploringFragment(mContext, japanGuideViewModel);
return localeExploringFragment;
default: Log.d(TAG, "default constructor so returning localeChoosingFragment"); localeChoosingFragment = new LocaleChoosingFragment(mContext, japanGuideViewModel); return localeChoosingFragment; }
}
@Override public int getItemCount() { return 2; } } } [/code] А вот localeChoosingFragment: [code]public class LocaleChoosingFragment extends Fragment {
public LocaleChoosingFragment() { Log.d(TAG, "EMPTY constructor called for localeChoosingFragment");
}
public LocaleChoosingFragment(Context mContext, JapanGuideViewModel japanGuideViewModel) { this.japanGuideViewModel = japanGuideViewModel; this.mContext = mContext; Log.d(TAG, "constructor called for localeChoosingFragment"); Toast.makeText(mContext, "Creating a new localeChoosingFragment", Toast.LENGTH_SHORT).show(); }
@Override public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate in localeChoosingFragment");
super.onCreate(savedInstanceState); Log.d(TAG, "creating a NEW LOCALECHOOSING RECYCLERVIEW");
}
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment
Log.d(TAG, "onCreateView called in LocalChoosingFragment");
public LocaleChoosingRecyclerViewAdaptor() { Log.d(TAG, "localeChoosingAdaptor created with empty constructor"); }
public LocaleChoosingRecyclerViewAdaptor(Context mContext, JapanGuideViewModel japanGuideViewModel) { this.mContext = mContext; this.japanGuideViewModel = japanGuideViewModel; Log.d(TAG, "localeChoosingAdaptor created with full constructor"); }
@NonNull @Override public LocaleChoosingAdaptorHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { Log.d(TAG, "oncreateviewholder in localechoosingfragment"); View view = LayoutInflater.from(mContext).inflate(R.layout.locale_recyclerview_holder, parent, false); return new LocaleChoosingAdaptorHolder(view); }
@Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { Log.d(TAG, "onBindViewHolder called in localeChoosingFragment. The position is " + position + " and the total size is " + getItemCount()); localeNameTextView = holder.itemView.findViewById(R.id.localeRecyclerviewHolderHeadingTextview); localeNameTextView.setText(japanGuideViewModel.getLocalesDetailsArray().getValue().get(position).getLocaleName()); localeDescriptionTextView = holder.itemView.findViewById(R.id.localeRecyclerviewHolderDescriptionTextView); if (japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getLocaleDescription() != null) { localeDescriptionTextView.setText(japanGuideViewModel.getLocalesDetailsArray().getValue().get(holder.getAdapterPosition()).getLocaleDescription()); }
} [/code] Я не ожидал, что RecyclerView в LocaleChoosingFragment вернется в первую позицию, когда наблюдатель в plannerFragment запускается наблюдателем в plannerFragment currentLocaleBeingViewed в Viewmodel. Все остальное работает как положено.
У меня есть ViewPager 2 внутри plannerFragment, который вызывает 2 фрагмента: один (localeChoosingFragment) содержит recyclerview, позволяющий пользователю выбирать языковой стандарт, а другой — для выбора мест в этом языковом стандарте...
У меня есть ViewPager 2 внутри plannerFragment, который вызывает 2 фрагмента: один (localeChoosingFragment) содержит recyclerview, позволяющий пользователю выбирать языковой стандарт, а другой — для выбора мест в этом языковом стандарте...
У меня возникла проблема с тем, чтобы ViewPager работал как вложенная часть навигации с нижней вкладкой навигации в Android Kotlin
это мой код:
MainActivity.kt
class MainActivity : AppCompatActivity() {
У меня возникла проблема с тем, чтобы ViewPager работал как вложенная часть навигации с нижней вкладкой навигации в Android Kotlin
это мой код:
MainActivity.kt
class MainActivity : AppCompatActivity() {
I'm a beginner using Android Studio for our project. How do I add an item of a recyclerView in a fragment into another fragment with a recyclerView in it? I can't figure out how to do it. Right now, the only way I could manually add an item to the...