我在名为SearchFragment
的活动中的视图寻呼机中有两个片段CreateFragment
和TicketManagementActivity
。现在,当用户按下SearchFragment
中的搜索按钮时,我希望SearchFragment
替换为SearchResultFragment
。然后,我应该可以在SeachResultFragment
中的CreateFragment
和ViewPager
之间滑动。此外,当我从SearchResultFragment
按回来时,我应该回到SearchFragment
。
现在,当我按下按钮时,我得到一个空白屏幕,而不是SearchResultFragment
的布局。当我按下时我会到SearchFragment
,但现在我必须单击按钮两次才能显示空白屏幕。现在,在双击后出现空白屏幕后,每当我滑动到CreateFragment
标签时,我都会得到一个空白屏幕,而不是CreateFragment
布局。
我看了很多关于SO的问题,但似乎没有一个问题对我有用。最有用的似乎是this question中的前两个答案,但第一个答案并不处理背压,我也无法实现它。第二个答案似乎非常可行,但我得到的错误是我在下面提到的。
我的主要TicketManagemementActivity
:
public class TicketManagementActivity extends FragmentActivity implements
ActionBar.TabListener {
ViewPager viewPager;
TabsPagerAdapter adapter;
ActionBar actionBar;
String[] tabs={"Search", "Create"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ticket_management);
viewPager=(ViewPager)findViewById(R.id.pager);
actionBar=getActionBar();
adapter=new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for(String tab_name : tabs){
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
}
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
//removed methods for menu creation and filling and placeholder fragment for brevity on SO
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
我的activity_ticket_management.xml
是在票务管理活动的onCreate中设置的布局,只包含viewpager
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
我的TabsPagerAdapter
课程延长了FragmentPagerAdapter
:
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int index) {
switch (index) {
case 0:
// Top Rated fragment activity
return new SearchFragment();
case 1:
// Games fragment activity
return new CreateFragment();
}
return null;
}
@Override
public int getCount() {
// get item count - equal to number of tabs
return 2;
}
}
我SearchFragment
的相关部分:
public class SearchFragment extends Fragment implements View.OnClickListener {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_search, container, false);
.
.//some widget initializations
.
return rootView;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ticket_search_btn: searchSigmaTickets();
break;
}
}
public void searchSigmaTickets(){
.
.
.
.//some operations
.
new SearchAsyncTask().execute();
}
}
private class SearchAsyncTask extends AsyncTask<Void, Void, Void>{
protected Void doInBackground(Void... params){
.
.//some more operation
.
}
protected void onPostExecute(Void param){
Fragment newFragment = new SearchResultFragment();
//Here I use getFragmentManager and not getChildFragmentManager
FragmentTransaction transaction = getFragmentManager().beginTransaction();
//HERE I try to replace the fragment. I'm not sure what id to pass, I pass the id of the main veiwpager in ticketmanagement activity
transaction.replace(R.id.pager, newFragment);
transaction.addToBackStack(null);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.commit();
}
}
}
如果我使用getChildFragmentManager
代替getFragmentManager
,我会在第二个回答中提到
06-25 06:55:32.045: E/AndroidRuntime(2797): java.lang.IllegalArgumentException: No view found for id 0x7f06003c (com.amberroad.sigmaticket:id/pager) for fragment SearchResultFragment{b2fed358 #0 id=0x7f06003c}
对于这个冗长的问题,我该怎么解决?
答案 0 :(得分:1)
Kartik,准备好对你的长篇问题进行冗长的回答。在viewpager中更换片段非常复杂,但是非常有可能并且看起来非常光滑。首先,您需要让viewpager本身处理删除和添加片段。发生的事情是当您替换SearchFragment内部的片段时,您的viewpager会保留其片段视图。所以你最终得到一个空白页面,因为当你尝试替换它时会删除SearchFragment。
解决方案是在viewpager中创建一个侦听器,该侦听器将处理在其外部进行的更改,因此首先将此代码添加到适配器的底部。
public interface nextFragmentListener {
public void fragment0Changed(String newFragmentIdentification);
}
然后,您需要在viewpager中创建一个私有类,当您想要更改片段时,该私有类变为listener
。例如,你可以添加这样的东西。请注意,它实现了刚刚创建的接口。因此,无论何时调用此方法,它都将运行下面类中的代码。
private final class fragmentChangeListener implements nextFragmentListener {
@Override
public void fragment0Changed(String fragment) {
//I will explain the purpose of fragment0 in a moment
fragment0 = fragment;
manager.beginTransaction().remove(fragAt0).commit();
switch (fragment){
case "searchFragment":
fragAt0 = SearchFragment.newInstance(listener);
break;
case "searchResultFragment":
fragAt0 = Fragment_Table.newInstance(listener);
break;
}
notifyDataSetChanged();
}
这里有两点需要指出:1)fragAt0是一个“灵活”的片段。它可以采用您提供的任何片段类型。这使它成为你最好的朋友,将位置0的片段更改为你想要的片段。 2)注意放在'newInstance(listener)constructor. These are how you will call
fragment0Changed(String newFragmentIdentification)`中的监听器。以下代码显示了如何在片段内创建侦听器。
static nextFragmentListener listenerSearch;
public static Fragment_Journals newInstance(nextFragmentListener listener){
listenerSearch = listener;
return new Fragment_Journals();
}
然后您可以调用onPostExecute
中的更改private class SearchAsyncTask extends AsyncTask<Void, Void, Void>{
protected Void doInBackground(Void... params){
.
.//some more operation
.
}
protected void onPostExecute(Void param){
listenerSearch.fragment0Changed("searchResultFragment");
}
}
这会触发viewpager内部的代码,将片段切换到零fragAt0
位置,成为新的searchResultFragment。在viewpager运行之前,还需要添加两个小块。
一个将在viewpager的getItem
覆盖方法中。
@Override
public Fragment getItem(int index) {
switch (index) {
case 0:
//this is where it will "remember" which fragment you have just selected. the key is to set a static String fragment at the top of your page that will hold the position that you had just selected.
if(fragAt0 == null){
switch(fragment0){
case "searchFragment":
fragAt0 = FragmentSearch.newInstance(listener);
break;
case "searchResultsFragment":
fragAt0 = FragmentSearchResults.newInstance(listener);
break;
}
}
return fragAt0;
case 1:
// Games fragment activity
return new CreateFragment();
}
现在没有这个最后一块,你仍然会得到一个空白页面。有点蹩脚,但它是viewPager的重要组成部分。您必须覆盖viewpager的getItemPosition
方法。通常,此方法将返回POSITION_UNCHANGED
,它告诉viewpager保持所有内容相同,因此永远不会调用getItem
将新片段放在页面上。这是你可以做的事情的一个例子
public int getItemPosition(Object object)
{
//object is the current fragment displayed at position 0.
if(object instanceof SearchFragment && fragAt0 instanceof SearchResultFragment){
return POSITION_NONE;
//this condition is for when you press back
}else if{(object instanceof SearchResultFragment && fragAt0 instanceof SearchFragment){
return POSITION_NONE;
}
return POSITION_UNCHANGED
}
就像我说的,代码非常复杂,但你基本上必须为你的情况创建一个自定义适配器。我提到的东西可以改变片段。浸泡所有东西可能需要很长时间,所以我会耐心等待,但这一切都有意义。完全值得花时间,因为它可以制作一个非常漂亮的应用程序。
这是处理后退按钮的金块。你把它放在你的MainActivity中
public void onBackPressed() {
if(mViewPager.getCurrentItem() == 0) {
if(pagerAdapter.getItem(0) instanceof FragmentSearchResults){
((FragmentSearchResults) pagerAdapter.getItem(0)).backPressed();
}else if (pagerAdapter.getItem(0) instanceof FragmentSearch) {
finish();
}
}
}
您需要在FragmentSearchResults内部创建一个名为backPressed()
的方法,该方法调用fragment0changed。这与我之前展示的代码一起将按下后退按钮。祝你的代码更改viewpager好运。它需要做很多工作,据我所知,没有任何快速的改编。就像我说的,你基本上是在创建一个自定义viewpager适配器,让它使用监听器处理所有必要的更改
以下是TabsPagerAdapter的所有代码。
public class TabsPagerAdapter extends FragmentPagerAdapter{
Fragment fragAt0;
fragmentChangeListener listener = new fragmentChangeListener();
FragmentManager manager;
static String fragment0 = "SearchFragment";
//when you declare the viewpager in your adapter, pass it the fragment manager.
public viewPager(FragmentManager fm) {
super(fm);
manager = fm;
}
private final class fragmentChangeListener implements nextFragmentListener {
@Override
public void fragment0Changed(String fragment) {
//I will explain the purpose of fragment0 in a moment
fragment0 = fragment;
manager.beginTransaction().remove(fragAt0).commit();
switch (fragment){
case "searchFragment":
fragAt0 = SearchFragment.newInstance(listener);
break;
case "searchResultFragment":
fragAt0 = Fragment_Table.newInstance(listener);
break;
}
notifyDataSetChanged();
}
}
@Override
public Fragment getItem(int index) {
switch (index) {
case 0:
//this is where it will "remember" which fragment you have just selected. the key is to set a static String fragment at the top of your page that will hold the position that you had just selected.
if(fragAt0 == null){
switch(fragment0){
case "searchFragment":
fragAt0 = FragmentSearch.newInstance(listener);
break;
case "searchResultsFragment":
fragAt0 = FragmentSearchResults.newInstance(listener);
break;
}
}
return fragAt0;
case 1:
// Games fragment activity
return new CreateFragment();
}
@Override
public int getCount() {
// Show 3 total pages.
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
String[] tab = {"Journals", "Charts", "Website"};
switch (position) {
case 0:
return tab[0].toUpperCase(l);
case 1:
return tab[1].toUpperCase(l);
case 2:
return tab[2].toUpperCase(l);
}
return null;
}
public int getItemPosition(Object object)
{
//object is the current fragment displayed at position 0.
if(object instanceof SearchFragment && fragAt0 instanceof SearchResultFragment){
return POSITION_NONE;
//this condition is for when you press back
}else if{(object instanceof SearchResultFragment && fragAt0 instanceof SearchFragment){
return POSITION_NONE;
}
return POSITION_UNCHANGED
}
public interface nextFragmentListener {
public void fragment0Changed(String fragment);
}