[英]Android ViewPager Not showing the right fragment
我目前正在嘗試實現一個簡單的ViewPager,它可以切換以各種方式(而不是通過滑動)觸發的片段。 我的應用程序嘗試從第二個片段轉到第三個片段時崩潰,因為它實際上跳過了GroupActivityFragment
並由於某種奇怪的原因而嘗試轉到GroupFrequencyFragment
。 我嘗試了許多不同的策略,但是如果不想使用滑動遍歷,則此ViewPager系統似乎非常復雜且有問題。
這是舉行ViewPager的活動
public class CreateGroupActivity extends FragmentActivity {
public static ViewPager viewPager;
private CreateGroupPagerAdapter pagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_group);
viewPager = findViewById(R.id.create_group_view_pager);
pagerAdapter = new CreateGroupPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
//Prevents swiping to next step.
viewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
@Override
public void onBackPressed() {
if (viewPager.getCurrentItem() == 0) {
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
} else {
// Otherwise, select the previous step.
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
}
}
}
這是用於創建不同片段的自定義尋呼機適配器
public class CreateGroupPagerAdapter extends FragmentStatePagerAdapter {
private static final String TAG = "CreateGroupPagerAdapter";
private static final int NUM_PAGES = 6;
public CreateGroupPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Log.i(TAG, "getItem: pos = " + position);
Fragment fragment = null;
switch (position) {
case 0:
fragment = new GroupFormatFragment();
break;
case 1:
fragment = new GroupStyleFragment();
break;
case 2:
fragment = new GroupActivityFragment();
break;
case 3:
fragment = new GroupFrequencyFragment();
break;
case 4:
fragment = new GroupSettingsFragment();
break;
case 5:
fragment = new GroupInviteFriendsFragment();
break;
}
// position = position + 1;
return fragment;
}
// this counts total number of tabs
@Override
public int getCount() {
return NUM_PAGES;
}
}
同樣,所有Fragments都從一個抽象類繼承,該抽象類具有用於告訴Viewpager切換片段的方法。
public abstract class GroupCreationFragment extends Fragment {
public ArrayList<String> itemTitles;
public ArrayList<String> itemDescriptions;
private static final String TAG = "GroupCreationFragment";
public GroupCreationFragment() {
// Required empty public constructor
}
@Override
public abstract View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
/**
* Sets the title of the fragment and then the filling content views.
*
* @param view
*/
public abstract void setFragmentViews(View view);
/**
* Tell the parent activity's ViewPager to set the current item.
*
*/
public void notifyPageChange() {
CreateGroupActivity.viewPager.setCurrentItem(CreateGroupActivity.viewPager.getCurrentItem()+1,true);
}
}
這是被跳過的GroupActivityFragment
類。
public class GroupActivityFragment extends GroupCreationFragment {
public GroupActivityFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_group_activity, container, false);
itemTitles = new ArrayList<>();
itemDescriptions = new ArrayList<>();
setFragmentViews(view);
return view;
}
@Override
public void setFragmentViews(View view){
itemTitles.add(getResources().getString(R.string.exercise_regularly));
itemDescriptions.add(getResources().getString(R.string.exercise_regularly_desc));
initRecyclerView(view);
}
private void initRecyclerView(View view) {
RecyclerView recyclerView = view.findViewById(R.id.group_activity_recycler_view);
GroupCreationRecyclerViewAdapter adapter = new GroupCreationRecyclerViewAdapter(getContext(), this, itemTitles, itemDescriptions, 2);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
}
}
還有用於處理前3個片段中的片段更改的GroupCreationRecyclerViewAdapter
類。
public class GroupCreationRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "GCRecyclerViewAdapter";
private GroupCreationFragment parentFragment;
private int pagePosition;
public ArrayList<String> itemTitles = new ArrayList<>();
public ArrayList<String> itemDescriptions = new ArrayList<>();
private Context context;
public GroupCreationRecyclerViewAdapter(Context context, GroupCreationFragment parentFragment, ArrayList<String> itemTitles, ArrayList<String> itemDescriptions, int pagePosition) {
this.itemTitles = itemTitles;
this.itemDescriptions = itemDescriptions;
this.context = context;
this.parentFragment = parentFragment;
this.pagePosition = pagePosition;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_group_creation_item, viewGroup, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
((ViewHolder) viewHolder).itemTitle.setText(itemTitles.get(i));
((ViewHolder) viewHolder).itemDescription.setText(itemDescriptions.get(i));
final int pos = i;
((ViewHolder) viewHolder).parentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Handle option choice.
handleItemOnClick(itemTitles.get(pos));
}
});
}
@Override
public int getItemCount() {
return itemTitles.size();
}
public void handleItemOnClick(String title) {
switch (title) {
case "Private Group":
GroupBuilder.getInstance().setFormat("private");
break;
case "Public Group":
break;
case "Accountability":
GroupBuilder.getInstance().setStyle("accountability");
break;
case "Competition":
break;
case "Exercise Regularly":
GroupBuilder.getInstance().setActivityType("exercise regularly");
break;
}
Log.i("GroupCreationRV", "handleItemOnClick: " + GroupBuilder.getInstance().toString());
Log.i(TAG, "notifyPageChange: getPagePosition = " + getPagePosition());
// Tell ViewPager to move to next page.
parentFragment.notifyPageChange();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView itemTitle;
public TextView itemDescription;
public ConstraintLayout parentLayout;
public ViewHolder(@NonNull View itemView) {
super(itemView);
itemTitle = itemView.findViewById(R.id.item_main_title);
itemDescription = itemView.findViewById(R.id.item_description);
parentLayout = itemView.findViewById(R.id.group_creation_item_layout);
}
}
public int getPagePosition() {
return pagePosition;
}
}
由於ViewPager
在被查看的片段之前創建了一個片段,因此GroupFrequencyFragment
正在GroupFrequencyFragment
之前的片段同時創建。 這產生了一個問題,因為需要填充變量才能在該片段上正確顯示它。 因此,我實現了一種方法,可以延遲特定視圖的完全初始化,直到用戶查看該片段為止。
public class GroupFrequencyFragment extends GroupCreationFragment {
private static final String TAG = "GroupFrequencyFragment";
private static TextView activityLabel;
public GroupFrequencyFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_group_frequency, container, false);
setFragmentViews(view);
return view;
}
@Override
public void setFragmentViews(View view) {
initFrequencyViews(view);
setActivityLabel();
}
public void setActivityLabel() {
if (GroupBuilder.getInstance().getActivityType() != null) {
String type = GroupBuilder.getInstance().getActivityType();
switch (type) {
case "exercise regularly":
// Set the right label
Log.i(TAG, "setActivityLabel: activityLabel = " + activityLabel);
activityLabel.setText("workouts every");
break;
default:
break;
}
}
}
private void initFrequencyViews(View view) {
activityLabel = view.findViewById(R.id.activity_label);
...
}
這是供ViewPager等待片段查看的onPageListener。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_group);
viewPager = findViewById(R.id.create_group_view_pager);
pagerAdapter = new CreateGroupPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
//Prevents swiping to next step.
viewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageSelected(int i) {
if (i == 3) {
CreateGroupPagerAdapter adapter = (CreateGroupPagerAdapter) viewPager.getAdapter();
GroupFrequencyFragment frequencyFragment = (GroupFrequencyFragment) adapter.getItem(3);
frequencyFragment.setActivityLabel();
}
}
@Override
public void onPageScrollStateChanged(int i) {
}
});
}
@Override
public void onBackPressed() {
if (viewPager.getCurrentItem() == 0) {
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
} else {
// Otherwise, select the previous step.
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
}
}
ViewPager
的默認配置包括優化,以急於創建“屏幕外”頁面。 這個想法是,當用戶在頁面之間滑動時,將頁面擴展到當前可見頁面的“任一側”將有助於平滑過渡。
https://developer.android.com/reference/android/support/v4/view/ViewPager#setoffscreenpagelimit
設置在空閑狀態下視圖層次結構中應保留到當前頁面任一側的頁面數。 [...] 此設置默認為1。
我從您的代碼中看到GroupActivityFragment
位於索引2, GroupFrequencyFragment
位於索引3。因此,當您導航至索引2時, GroupActivityFragment
和GroupFrequencyFragment
將同時創建。
不幸的是,您不能將此數字設置為小於1。從源代碼中 :
if (limit < DEFAULT_OFFSCREEN_PAGES) { Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + DEFAULT_OFFSCREEN_PAGES); limit = DEFAULT_OFFSCREEN_PAGES; }
這意味着您必須將GroupFrequencyFragment
移到遠離GroupActivityFragment
足夠遠的位置,以便不能同時創建它,或者必須對實現進行重新設計,以便同時創建這不是問題。
或者,您可以完全停止使用ViewPager
。 如果您不希望用戶在頁面之間滑動,為什么不簡單地使用FragmentTransaction
並根據需要replace()
您的片段呢?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.