Обновить фрагмент из ViewPager
У меня есть Activity
с ViewPager
. У меня также есть Dialog
, который будет извлекать список с некоторыми элементами, которые пользователь выберет. Теперь, как я могу обновить Fragment
, где Элементы должны отображаться как новые представления, прикрепленные к этому фрагменту?
Вот мой адаптер ViewPager
:
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return 1;
}
@Override
public android.support.v4.app.Fragment getItem(int position) {
switch (position) {
case 0:
return new Fragment1();
default:
return null;
}
}
}
Теперь, вот Fragment
:
public class Fragment1 extends Fragment{
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
}
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
@Override
public ViewGroup onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
ViewGroup view = (ViewGroup)inflater.inflate(R.layout.screen1, container, false);
}
return view;
}
}
Это метод, который я хочу использовать для добавления элементов в мой Fragment
private void addItem() {
// Instantiate a new "row" view.
final ViewGroup[] newViews = new ViewGroup[selectedItems.length];
for(int i = 0; i < selectedItems.length; i++){
newViews[i] = (ViewGroup) LayoutInflater.from(this).inflate(
R.layout.animated_layout_item, mContainerView, false);
// Set the text in each new row.
((TextView) newViews[i].findViewById(android.R.id.text1)).setText(selectedItems[i]);
// Because mContainerView has android:animateLayoutChanges set to true,
// adding this view is automatically animated.
mContainerView.addView(newViews[i], 0);
// Set a click listener for the "X" button in the row that will remove the row.
OnClickListener listener = new MyAddItemListener(newViews[i], mContainerView, this);
newViews[i].findViewById(R.id.delete_button).setOnClickListener(listener);
}
}
Ответы
Ответ 1
Обновить фрагмент из ViewPager
Вам нужно реализовать метод getItemPosition(Object obj)
.
Этот метод вызывается, когда вы вызываете
notifyDataSetChanged()
на ViewPagerAdaper
. Неявно этот метод возвращает значение POSITION_UNCHANGED
, что означает что-то вроде этого:
"Фрагмент - это то, где он должен быть, поэтому ничего не меняйте".
Итак, если вам нужно обновить Фрагмент, вы можете сделать это с помощью
- Всегда возвращайте метод
POSITION_NONE
из getItemPosition()
. Это
означает: "Фрагмент должен всегда воссоздаваться"
- Вы можете создать некоторый метод update(), который будет обновлять ваши
Фрагмент (фрагмент обрабатывает сами обновления)
Пример второго подхода:
public interface Updateable {
public void update();
}
public class MyFragment extends Fragment implements Updateable {
...
public void update() {
// do your stuff
}
}
И в FragmentPagerAdapter вы сделаете что-то вроде этого:
@Override
public int getItemPosition(Object object) {
MyFragment f = (MyFragment ) object;
if (f != null) {
f.update();
}
return super.getItemPosition(object);
}
И если вы выберете первый подход, это может выглядеть так:
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
Примечание: Стоит подумать о том, какой подход вы подберете.
Ответ 2
Я столкнулся с проблемой несколько раз, чтобы в этом случае всегда избегать FragmentPagerAdapter и использовать FragmentStatePagerAdapter.
Это работает для меня. Я надеюсь, что это сработает и для вас.
Ответ 3
Я реализую демонстрацию приложения после ответа Саймона.
Только для тех, кто ищет этот вопрос.
Вы можете получить исходный код на GitHub
![введите описание изображения здесь]()
Ответ 4
В вашем PagerAdapter переопределить getItemPosition
@Override
public int getItemPosition(Object object) {
// POSITION_NONE makes it possible to reload the PagerAdapter
return POSITION_NONE;
}
После этого добавьте viewPager.getAdapter(). notifyDataSetChanged(); этот код, как показано ниже
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
viewPager.getAdapter().notifyDataSetChanged();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
должен работать.
Ответ 5
Очень просто переопределить метод в фрагменте:
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
actionView();
}
else{
//no
}
}
Ответ 6
Вы можете обновить фрагмент двумя способами,
Первый способ
как @Sajmon
Вам нужно реализовать метод getItemPosition(Object obj)
.
Этот метод вызывается, когда вы вызываете
notifyDataSetChanged()
Вы можете найти пример в Github и более подробную информацию в этом пост.
![введите описание изображения здесь]()
Второй способ
Мой подход к обновлению фрагментов в viewpager заключается в использовании метода setTag()
для любого инстанцированного представления в методе instantiateItem()
. Поэтому, когда вы хотите изменить данные или сделать недействительным требуемое представление, вы можете вызвать метод findViewWithTag()
на ViewPager, чтобы получить ранее созданное представление и изменить/использовать его, как вы хотите, без необходимости удаления/создания нового представления каждый раз, когда вы хотите обновить некоторое значение.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Object object = super.instantiateItem(container, position);
if (object instanceof Fragment) {
Fragment fragment = (Fragment) object;
String tag = fragment.getTag();
mFragmentTags.put(position, tag);
}
return object;
}
public Fragment getFragment(int position) {
Fragment fragment = null;
String tag = mFragmentTags.get(position);
if (tag != null) {
fragment = mFragmentManager.findFragmentByTag(tag);
}
return fragment;
}
Вы можете найти пример в Github или более подробную информацию в этом сообщение:
![введите описание изображения здесь]()
Ответ 7
Принятый ответ не понимает, поэтому добавлено простое решение. после длительной борьбы
найти Рабочее решение.
Просто сообщите об этом адаптеру, он работает потрясающе,
Код ссылки
void setAdapter(int position) {
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
// when notify then set manually current position.
viewPager.setCurrentItem(position);
pagerAdapter.notifyDataSetChanged();
}
вызывают этот код при настройке адаптера и когда вы хотите обновить интерфейс.
В своем фрагменте добавьте этот код для обновления
((YourActivityName) getContext()).setAdapter(selectedTabPosition);
Используйте instanceof
для контекста трансляции.
Этот общий код помогает только тем, кто находит решение.
Ответ 8
Очень простое, но эффективное решение обновить виды фрагментов. Используйте метод setUserVisibleHint()
. Он будет вызван, когда фрагмент будет видимым для пользователя. Там вы можете обновить наш вид (setText()
или setVisibility()
и т.д.)
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
//Write your code to be executed when it is visible to user
}
}
Это сработало в моем случае. Надеюсь, поможет!
Ответ 9
Если вы используете Kotlin, вы можете сделать следующее:
1. По первому, вам следует создать Interface
и внедрить его в ваш Fragment
interface RefreshData {
fun refresh()
}
class YourFragment : Fragment(), RefreshData {
...
override fun refresh() {
//do what you want
}
}
2. Следующий шаг - добавление OnPageChangeListener
в ваш ViewPager
viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) { }
override fun onPageSelected(position: Int) {
viewPagerAdapter.notifyDataSetChanged()
viewPager.currentItem = position
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { }
})
3. переопределить getItemPosition
в вашем Adapter
override fun getItemPosition(obj: Any): Int {
if (obj is RefreshData) {
obj.refresh()
}
return super.getItemPosition(obj)
}
Ответ 10
Возможно, ваш метод добавления элементов в фрагмент должен быть общедоступным (помещен в желаемый фрагмент) и должен иметь параметр того же типа, что и selectedItems..
Это сделает его видимым из активности, в котором будет выбран массив элементов и voila.
p.s. лучше назовите его addItemsFromArray(typeOfSelectedItems[] pSelectedItems)
причина name addItem()
довольно непривычно
Изменить: stackoverflow просто предложил похожую тему:) Посмотрите здесь для детальной реализации идеи..:)
Ответ 11
1) Создайте обработчик в фрагменте, который вы хотите обновить.
public static Handler sUpdateHandler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
sUpdateHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// call you update method here.
}
};
}
2) В Activity/Fragment/Dialog, где бы вы не вызвали вызов обновления, получите ссылку на этот обработчик и отправьте сообщение (сообщив об обновлении вашего фрагмента)
// Check if the fragment is visible by checking if the handler is null or not.
Handler handler = TaskTabCompletedFragment.sUpdateHandler;
if (handler != null) {
handler.obtainMessage().sendToTarget();
}
Ответ 12
у меня было 4 фрагмента в ViewPager, но я хотел обновить только один фрагмент "FavoriteFragment" в позиции 0 viewPager, каждый раз, когда пользователь нажимает на этот фрагмент. но ни один из приведенных выше кодов не помог мне перезагрузить только тот фрагмент, который я хочу. так что я попробовал это, и это работает для меня:
в моем любимом фрагменте я переопределил onResume()
@Override
public void onResume() {
super.onResume();
updateUI(); // code to update the UI in the fragment
}
в Activity, где размещается viewPager, переопределите addOnPageChangeListener()
и добавьте этот код
mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
if(position == 0) { // 0 = the first fragment in the ViewPager, in this case, the fragment i want to refresh its UI
FavoritesFragment fragment = (FavoritesFragment) mViewPager.getAdapter().instantiateItem(mViewPager, position);
fragment.onResume(); // here i call the onResume of the fragment, where i have the method updateUI() to update its UI
mViewPager.getAdapter().notifyDataSetChanged();
}
}
});
и это прекрасно работает для меня, чтобы обновить/перезагрузить только один фрагмент, который я хочу.
Ответ 13
Поскольку ни один из приведенных выше ответов не помог мне, вот мое решение:
Я объединил POSITION_NONE
с загрузкой в setUserVisibleHint(boolean isVisibleToUser)
вместо onStart()
Как видно здесь: fooobar.com/info/13824/...
Во Fragment
:
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// load data here
}else{
// fragment is no longer visible
}
}
и в FragmentStatePagerAdapter
как видно из верхнего ответа от Саймона Дорокиака fooobar.com/info/133497/...:
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
Теперь фрагменты загружают данные в свои представления каждый раз, когда они показываются пользователю.