Обновление TextView в ViewPager из другого фрагмента
Я пытаюсь обновить TextView во фрагменте, нажимая кнопку другого фрагмента.
На самом деле я реализовал функцию обратного вызова в Activity, и она работает, поскольку Logcat сообщает, что текст в TextView был изменен. Проблема в том, что Textview, показанный в первом фрагменте, не обновляется до нового значения! Это как фрагмент должен быть обновлен или что-то...
Вот код активности ActionBarTabsPager:
import java.util.ArrayList;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentManager.OnBackStackChangedListener;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ActionBar.Tab;
import android.support.v4.app.SupportActivity;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.TextView;
/**
* Demonstrates combining the action bar with a ViewPager to implement a tab UI
* that switches between tabs and also allows the user to perform horizontal
* flicks to move between the tabs.
*/
public class ActionBarTabsPager extends FragmentActivity implements SecondFragment.OnButtonClickedXListener{
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
FragmentManager fm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.actionbar_tabs_pager);
if (savedInstanceState == null) {
Fragment newFragment = new FirstFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.abs__custom, newFragment, "FirstFragment").commit();
Fragment newFragment2 = new FirstFragment();
FragmentTransaction ft2 = getSupportFragmentManager().beginTransaction();
ft2.add(R.id.abs__custom, newFragment2, "SecondFragment").commit();
}
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab1 = getSupportActionBar().newTab().setText("Fragment 1");
ActionBar.Tab tab2 = getSupportActionBar().newTab().setText("Fragment 2");
//ActionBar.Tab tab3 = getSupportActionBar().newTab().setText("Fragment 1");
//ActionBar.Tab tab4 = getSupportActionBar().newTab().setText("Fragment 2");
mViewPager = (ViewPager)findViewById(R.id.pager);
mTabsAdapter = new TabsAdapter(this, getSupportActionBar(), mViewPager);
mTabsAdapter.addTab(tab1, FirstFragment.class);
mTabsAdapter.addTab(tab2, SecondFragment.class);//LoaderCursorSupport.CursorLoaderListFragment.class);
//mTabsAdapter.addTab(tab3, FirstFragment.class);//LoaderCustomSupport.AppListFragment.class);
//mTabsAdapter.addTab(tab4, SecondFragment.class);//LoaderThrottleSupport.ThrottledLoaderListFragment.class);
if (savedInstanceState != null) {
getSupportActionBar().setSelectedNavigationItem(savedInstanceState.getInt("index"));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("index", getSupportActionBar().getSelectedNavigationIndex());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
public class TabsAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<String> mTabs = new ArrayList<String>();
public TabsAdapter(FragmentActivity activity, ActionBar actionBar, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = actionBar;
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss) {
mTabs.add(clss.getName());
mActionBar.addTab(tab.setTabListener(this));
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
return Fragment.instantiate(mContext, mTabs.get(position), null);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
}
@Override
public void OnButtonClickedX(View v) {
if (v==findViewById(R.id.button1)){
Log.i("TRIGGERED","TRIGGERED");
FirstFragment ff = (FirstFragment) getSupportFragmentManager().findFragmentByTag("FirstFragment");
View root = ff.getView();
TextView tv = (TextView) root.findViewById(R.id.textView1);
Log.i("Text before Edit",""+tv.getText());
tv.setText("MODIFIED");
Log.i("Text after Edit",""+tv.getText());
}
// TODO Auto-generated method stub
}
}
FirstFragment:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FirstFragment extends Fragment {
int mNum;
/**
* Create a new instance of FirstFragment, providing "num"
* as an argument.
*/
static FirstFragment newInstance(int num) {
FirstFragment f = new FirstFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
/**
* When creating, retrieve this instance's number from its arguments.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments() != null ? getArguments().getInt("num") : 1;
}
/**
* The Fragment's UI is just a simple text view showing its
* instance number.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.myfrag1, container, false);
return v;
}
}
SecondFragment:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.SupportActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
public class SecondFragment extends Fragment {
int mNum;
OnButtonClickedXListener mListener;
/**
* Create a new instance of CountingFragment, providing "num"
* as an argument.
*/
static SecondFragment newInstance(int num) {
SecondFragment f = new SecondFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
/**
* When creating, retrieve this instance's number from its arguments.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments() != null ? getArguments().getInt("num") : 1;
}
/**
* The Fragment's UI is just a simple text view showing its
* instance number.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.myfrag2, container, false);
View button1 = v.findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mListener.OnButtonClickedX(v);
// TODO Auto-generated method stub
}
});
return v;
}
public interface OnButtonClickedXListener{
public void OnButtonClickedX(View v);
}
@Override
public void onAttach(SupportActivity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
try {
mListener = (OnButtonClickedXListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnButtonClickedXListener");
}
}
}
myfrag1.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="No String"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
myfrag2.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="Button" />
</LinearLayout>
РЕДАКТИРОВАТЬ:
Даже если установить значение 0 на ContainerViewId в ft.add(), это никак не повлияет на окончательный рендеринг. Так что я думаю, что рендеринг управляется
mTabsAdapter.addTab(tab1, FirstFragment.class);
mTabsAdapter.addTab(tab2, SecondFragment.class);
Во всяком случае, проблема остается прежней.
Вот actionbar_tabs_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
4 ответа
РЕШИТЬ!
Переопределение instantiateItem() в TabsAdapter и добавление ViewPager в качестве ContainerViewID в FragmentTransaction сделало это!
Вот и функционирует весь FragmentActivity!
import java.util.ArrayList;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentManager.OnBackStackChangedListener;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ActionBar.Tab;
import android.support.v4.app.SupportActivity;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.TextView;
/**
* Demonstrates combining the action bar with a ViewPager to implement a tab UI
* that switches between tabs and also allows the user to perform horizontal
* flicks to move between the tabs.
*/
public class ActionBarTabsPager extends FragmentActivity implements SecondFragment.OnButtonClickedXListener{
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
FragmentManager fm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("ONCREATE START","ONCREATE START");
setContentView(R.layout.actionbar_tabs_pager);
if (savedInstanceState == null) {
Fragment newFragment = new FirstFragment();
Fragment newFragment2 = new SecondFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.pager, newFragment, "FirstFragment");
ft.add(R.id.pager, newFragment2, "SecondFragment");
ft.commit();
}
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab1 = getSupportActionBar().newTab().setText("Fragment 1");
ActionBar.Tab tab2 = getSupportActionBar().newTab().setText("Fragment 2");
//ActionBar.Tab tab3 = getSupportActionBar().newTab().setText("Fragment 1");
//ActionBar.Tab tab4 = getSupportActionBar().newTab().setText("Fragment 2");
mViewPager = (ViewPager)findViewById(R.id.pager);
mTabsAdapter = new TabsAdapter(this, getSupportActionBar(), mViewPager);
mTabsAdapter.addTab(tab1, FirstFragment.class);
mTabsAdapter.addTab(tab2, SecondFragment.class);//LoaderCursorSupport.CursorLoaderListFragment.class);
//mTabsAdapter.addTab(tab3, FirstFragment.class);//LoaderCustomSupport.AppListFragment.class);
//mTabsAdapter.addTab(tab4, SecondFragment.class);//LoaderThrottleSupport.ThrottledLoaderListFragment.class);
if (savedInstanceState != null) {
getSupportActionBar().setSelectedNavigationItem(savedInstanceState.getInt("index"));
}
Log.i("ONCREATE END","ONCREATE END");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.i("onSaveInstanceState START","onSaveInstanceState START");
super.onSaveInstanceState(outState);
outState.putInt("index", getSupportActionBar().getSelectedNavigationIndex());
Log.i("onSaveInstanceState END","onSaveInstanceState END");
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
public class TabsAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<String> mTabs = new ArrayList<String>();
private FragmentTransaction mCurTransaction = null;
public TabsAdapter(FragmentActivity activity, ActionBar actionBar, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = actionBar;
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss) {
Log.i("addTab","addTab");
mTabs.add(clss.getName());
mActionBar.addTab(tab.setTabListener(this));
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Object instantiateItem(View container, int position) {
if (mCurTransaction == null) {
mCurTransaction = getSupportFragmentManager().beginTransaction();
}
// TODO Auto-generated method stub
Fragment fragment = getItem(position);
if (fragment!=null){
Log.i("Fragment Found!","Fragment Found! "+fragment.getTag());
mCurTransaction.attach(fragment);
}
return fragment;//super.instantiateItem(container, position);
}
@Override
public Fragment getItem(int position) {
Log.i("getItem","getItem");
if (position==0)
{Log.i("position=0","position=0");
return getSupportFragmentManager().findFragmentByTag("FirstFragment");}
else if (position==1)
{Log.i("position=1","position=1");
return getSupportFragmentManager().findFragmentByTag("SecondFragment");}
else return null;//Fragment.instantiate(mContext, mTabs.get(position), null);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
}
@Override
public void OnButtonClickedX(View v) {
if (v==findViewById(R.id.button1)){
Log.i("TRIGGERED","TRIGGERED");
FirstFragment ff = (FirstFragment) getSupportFragmentManager().findFragmentByTag("FirstFragment");
View root = ff.getView();
TextView tv = (TextView) root.findViewById(R.id.textView1);
Log.i("Text before Edit",""+tv.getText());
tv.setText("MODIFIED");
Log.i("Text after Edit",""+tv.getText());
}
// TODO Auto-generated method stub
}
}
Спасибо vbsteven!
Я предполагаю, что фрагменты, которые вы видите на экране, - это не фрагменты, которые вы добавляете вручную с тегами "FirstFragment" и "SecondFragment", а фрагменты, которые добавляются методом getItem вашего TabsAdapter.
Если вы посмотрите на его реализацию, он создает новые фрагменты.
@Override
public Fragment getItem(int position) {
return Fragment.instantiate(mContext, mTabs.get(position), null);
}
Эти вновь созданные фрагменты добавляются в FragmentManager с помощью пользовательских тегов, созданных в FragmentPagerAdapter (который расширяет TabsAdapter).
Пожалуйста, опубликуйте также actionbar_tabs_pager.xml.
Не знаю, решит ли это ваши проблемы, но в этой части кода вы добавляете FirstFragment() для обоих фрагментов...
Fragment newFragment = new FirstFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.abs__custom, newFragment, "FirstFragment").commit();
Fragment newFragment2 = new FirstFragment();
FragmentTransaction ft2 = getSupportFragmentManager().beginTransaction();
ft2.add(R.id.abs__custom, newFragment2, "SecondFragment").commit();
... и вы могли бы написать это более просто так:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.abs__custom, newFragment, "FirstFragment");
ft.add(R.id.abs__custom, newFragment2, "SecondFragment");
ft.commit();
Я предполагаю, что это случай "перекрывающихся" фрагментов - не редкость для тех, кто впервые пробует фрагменты. Каждый раз, когда вы повторно отображаете фрагмент (отобразите фрагмент, покажите другой, затем вернитесь к первому отображенному фрагменту), вы создаете новый фрагмент за видимым фрагментом. "Зеркальный фрагмент" остается сверху, блокируя ваш взгляд на фрагмент позади него. Только прокрутив этот фрагмент, вы увидите, что фрагмент позади действительно обновляется.
В большинстве случаев это просто случай, когда вы повторяете то, что вы делали в XML, в своей FragmentActivity. Опубликуйте свой макет XML, чтобы профессионалы по фрагментам могли лучше диагностировать вашу проблему.