【问题标题】:How to properly use ViewPager in android如何在android中正确使用ViewPager
【发布时间】:2017-04-14 00:11:53
【问题描述】:

我想做一个测验应用程序。到目前为止,我有 3 个活动 - 家庭、测验、得分。由于测验活动包含多个等效视图(图像标题、问题和 4 个答案按钮),我做了一些阅读并决定 ViewPagerFragmentStatePagerAdapter 显示就可以了。所以我制作了一个xml 模板并膨胀了几个测试视图,一切看起来都很好,直到我开始处理用户交互。

我想模拟一个切换按钮,每个问题只有一个正确答案,因此选择一个按钮应取消选择前一个按钮(如果有)。当按下按钮时,我更改了我的Question model,然后我找到所有带有findViewById 的按钮并重置它们的滤色器。然后我将该过滤器重新设置在我选择的按钮上。为了确定要更新哪个问题模型,我使用了我在模板根视图中设置的当前fragment 位置(使用setTag,在片段的 onCreate 中)。

这就是我如何称呼我的片段:

public Fragment getItem(int position) {
     Question question = Repository.findById(position);
     int correctAnswerBtnId;
     switch (question.getCorrectAnswerIndex()) {
         case 0: correctAnswerBtnId = R.id.quiz_answer_0_btn; break;
         case 1: correctAnswerBtnId = R.id.quiz_answer_1_btn; break;
         case 2: correctAnswerBtnId = R.id.quiz_answer_2_btn; break;
         case 3: correctAnswerBtnId = R.id.quiz_answer_3_btn; break;
    this.ACTIVITY_ROOT.setTag(question.getID());

    Fragment fragment = new QuestionFragment();
    Bundle args = new Bundle();
    args.putSerializable(QuestionFragment.QUESTION, question);
    fragment.setArguments(args);

    return fragment;

}

我的 QuestionFragment onCreateView 是按照文档:

public View onCreateView(
        LayoutInflater inflater,
        ViewGroup container,
        Bundle questionData) {

    this.rootView = inflater.inflate(
            R.layout.layout_question_template,
            container,
            false);

    Bundle args = getArguments();
    this.question = (Question) args.getSerializable(QuestionFragment.QUESTION);
    populateInflatable();

    rootView.findViewById(R.id.layout_question_template_root).setTag(this.question.getID());
    return rootView;
}

populateInflatable 中,我使用this.rootViewfintViewById 并用我的问题数据填充它。然后我更改按钮的颜色,如果从问题中选择了一个。

点击按钮我打电话给selectAnserButton

public void selectAnswerButton(View selectedButton) {
    int questionId =
            (int) this.activityRoot.findViewById(
                    R.id.layout_question_template_root).getTag(); //??
    unSelectAllButtons();
    changeColor(selectedButton);
    Repository.findById(questionId).selectAnswer(selectedButton.getId());
}

其中unSelectAllButtons 代表四个按钮上的buttonToUnSelect.getBackground().clearColorFilter();。而Repository 只是一个带有示例问题数据的static 类。

当我有不止一种观点时,一切都变得非常错误。在每个片段上,我使用相同的视图 ID 膨胀相同的 xml,正如我定义的那样。而且据我所知,调用findViewById 不会检索一个,而是从我当前检索具有该ID 的所有视图,而且还从我的上一个和下一个fragment 检索。所以每次我想选择我当前的fragment 的视图时,我也会修改上一个和下一个fragments 中的相同视图。你可以想象这是多么有问题。这让我觉得我犯了一个根本性的错误,因为我不认为应该有多个View 和相同的ID

我真的不明白我应该如何使用 ViewPager 来做到这一点。在这一点上,感觉就像我正在尝试制作木雕,但我正在将框架砍成碎片。使用 ViewPager 一定有更好的方法来做到这一点。

已解决:感谢 Soo Chun Jung 指出我的答案。简而言之,它对我有用的是:

  1. 将我的Question model id 传递给带有Bundle 的每个片段。
  2. 将每个片段存储在ArrayMap 中,片段位置为key,片段为value
  3. 现在很容易从我的selectAnswer 函数中获取每个片段:首先使用myViewPager.getCurrentItem 获取当前片段的位置,然后调用getter 函数返回当前位置上的片段。
  4. 现在我有了片段,我可以轻松更改其按钮,因为它们被保存为私有字段,在“onCreateView”方法中分配。

【问题讨论】:

标签: android android-fragments android-viewpager templating


【解决方案1】:

希望对你有帮助~



适配器

class CustomAdapter extends FragmentPagerAdapter {
private final String[] TITLES = {"A", "B"};
private final String TAG = CustomAdapter.class.getSimpleName();

private final ArrayList<Fragment> mFragments;

private final FragmentManager fm;

public CustomAdapter(FragmentManager fm) {
    super(fm);
    mFragments = new ArrayList<>(getCount());
    this.fm = fm;
}


@Override
public CharSequence getPageTitle(int position) {
    return TITLES[position];
}

@Override
public int getCount() {
    return TITLES.length;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    Log.d(TAG, "destroyItem position = " + position);
    mFragments.remove(object);
    super.destroyItem(container, position, object);
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    mFragments.add((Fragment) object);
    return object;
}

@Override
public Fragment getItem(int position) {
    Log.d(TAG, "getItem position = " + position);
    if (position == 0) {
        return MyFragmentA.newInstance();
    } else if (position == 1) {
        return MyFragmentB.newInstance();
    }
    return null;
}

public MyFragmentA getMyFragmentA() {
    synchronized (mFragments) {
        for (Fragment f : mFragments) {
            if (f instanceof MyFragmentA) {
                return (MyFragmentA) f;
            }
        }
    }
    return null;
}

public MyFragmentB getMyFragmentB() {
    synchronized (mFragments) {
        for (Fragment f : mFragments) {
            if (f instanceof MyFragmentB) {
                return (MyFragmentB) f;
            }
        }
    }
    return null;
} 
}



片段类

  public class MyFragmentB extends Fragment {

...


    public updateYourUI(){
        //update something
    }
}



用法

mPager = (CustomViewPager) findViewById(R.id.pager);
mAdapter = new CustomAdapter(getChildFragmentManager());
mPager.setAdapter(mAdapter);


mAdapter.getMyFragmentB().updateYourUI();

如果您只有一种 Fragment,请在下方发表评论。你可以像这样修改一些函数。

public static MyFragmentB newInstance(int ID) {
    MyFragmentB fragment = new MyFragmentB();
    Bundle bundle = new Bundle();
    bundle.putInt("ID", ID);
    fragment.setArguments(bundle);
    return fragment;
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    myID = getArguments().getInt("ID");
    ....
}

public int getMyID() {
    return myID;
}





public MyFragmentB getMyFragmentByID(String id) {
    synchronized (mFragments) {
        for (Fragment f : mFragments) {
            if (f instanceof MyFragmentB) {
                MyFragmentB temp = (MyFragmentB)f;
                if(temp.getID.equals(id){
                    return (MyFragmentB) f;
                }

            }
        }
    }
    return null;
}

【讨论】:

  • 感谢您的回答。我会尽快尝试一下。我不明白为什么getItem 硬编码为具体数量的项目?另外,我如何使用 Fragment 实例来更新我的 UI?这可以解决很多问题,但我也浏览了Fragment 文档,但找不到答案。
  • 刚刚有了一个想法:如果我在 onCreateView 方法中将每个片段的 UI 视图设置为他的私有字段,那么在我访问当前视图片段后,我可以通过 getter 访问它们,如您所示。这行得通吗?
  • 我的问题是我有多个相同Fragment 的实例。那么如何区分它们呢?我需要为片段本身设置某种 Id。
  • 对不起,我英语不好。这可能会造成误解。无论如何,我更新了我的答案。请检查。
  • 好吧,当然使用Bundle。非常感谢。我会一坐下就试试这个,当我开始工作时会标记为已接受。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-11
  • 2016-03-21
  • 1970-01-01
相关资源
最近更新 更多