Страницы

Поиск по вопросам

воскресенье, 15 декабря 2019 г.

Изменить fragment 2 из fragment 1

#java #android #android_fragment #fragment_manager


Условия: Имеется приложение с Activity и тремя fragment'ами, которые можно листать
смахивая влево - вправо как страницы (Этот эффект осуществляется благодаря ViewPager).

На экране всегда виден один из трёх фрагментов. При этом, при перелистывании на любой
из фрагментов, следующий за ним (если он существует) автоматически подгружается, предыдущий
остаётся в памяти, остальные - выгружаются из памяти.

То есть работает так:


Когда виден фрагмент 1: 1 (загружен/видно) - 2 (подгружен)       - 3 (выгружен)
Когда виден фрагмент 2: 1 (подгружен)       - 2 (загружен/видно) - 3 (подгружен)
Когда виден фрагмент 3: 1 (выгружен)       - 2 (подгружен)       - 3 (загружен/видно)




Код создания фрагментов (в Activity):

public class MainActivity extends FragmentActivity
{
    public final int FRAGMENT_ONE = 0; //идентификатор первого фрагмента
    public final int FRAGMENT_TWO = 1; //идентификатор второго фрагмента
    public final int FRAGMENT_THREE = 2; //идентификатор третьего фрагмента
    /** список фрагментов для отображения. */
    private final List _fragments = new ArrayList();


                               *** Остальной код ***


    @Override
    public void onResume()
    {
        super.onResume();

        //Создаем фрагменты.
        _fragments.add(FRAGMENT_ONE, new FirstFragment());
        _fragments.add(FRAGMENT_TWO, new SecondFragment());
        _fragments.add(FRAGMENT_THREE, new ThirdFragment());

        // Настройка фрагментов, определяющих количество фрагментов, экраны и название.
        FragmentPagerAdapter MainAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {

            @Override
            public int getCount() {return 3;} //Получаем количество фрагментов

            @Override
            public Fragment getItem(final int position) {return _fragments.get(position);}

            @Override
            public CharSequence getPageTitle(final int position) {

                switch (position) {
                    case FRAGMENT_ONE:
                        return "Title One";
                    case FRAGMENT_TWO:
                        return "Title Two";
                    case FRAGMENT_THREE:
                        return "Title three";
                    default:
                        return null;
                }
            }
        };

        ViewPager pager = (ViewPager) findViewById(R.id.pager); //Инициализируем
ViewPager
        pager.setAdapter(MainAdapter); //Устанавливаем Adapter для Viewpager


        int startPage = 1

        pager.setCurrentItem(startPage); //На каком фрагменте будет открываться 
    }

}




Задача: На каждом фрагменте есть картинка и кнопка. При нажатии на кнопку видимого
фрагмента, на остальных фрагментах должна поменяться картинка.


  С фрагментами которые выгружены - проблем нет. Перед тем как загрузится,
  они проверяют нужно ли менять картинку и, если нужно,
  подгружаются уже с изменённой картинкой:

         //Проверяем нужно ли менять картинку
        int ActivePage = strorageFileExemp.getInt(APP_STORAGE_LAST_PAGE, 8);
        if (ActivePage == 1 || ActivePage == 2)
        {
            ImageView MyImageView = view.findViewById(R.id.my_imageview_id);
            MyImageView.setImageResource(R.drawable.my_image);
        }



Проблема: Проблема имеется лишь с фрагментами, которые подгружены, но ещё не видны.
Не могу понять как поменять у них картинку, ведь они подгрузились, но всё ещё как бы null.


  Допустим, возьмём случай, когда виден фрагмент 1:
  
  1(загружен/видно) - 2(подгружен) - 3 (выгружен). 
  
  Я нажимаю кнопку на фрагменте 1. Фрагмент 3 изменит картинку, когда будет загружаться,
а вот в уже подгруженном, но ещё не видном фрагменте 2 не понимаю как поменять картинку.


Yellastro предложил рабочее, но не самое лучшее решение. Оно достаточно сложное и
создаёт свои неудобства. Поэтому вопрос всё ещё открыт и новые предложения активно
рассматриваются.
    


Ответы

Ответ 1



В вашем случае, когда три разных класса делают по сути одно и тоже (провоцируют смену картинок на остальных фрагментах и меняют свою картинку по какому то внешнем условию), лучше будет сделать просто для них суперкласс, примерно такой: public abstract class PictureChangingFragment extend Fragment { private MainActivity mActivity; //Надо запросить в конструкторе Активность, которая будет иметь ссылки на все фрагменты public PictureChangingFragment(MainActivity fActivity) { super(); mActivity = fActivity; } public void onChangePicture(ImageView fImageView) { //ваш код смены картинки у конкретного фрагмента } //Этот метод должен вызываться когда вы нажимаете на текущую картинку, или //когда еще вы захотите поменять картинки на соседних фрагментах public void changePictureOnOtherFragments() { //Теперь мы можем тупо через главную активность обратиться // ко всем остальным фрагментам и поменять на ни картинки for ( PictureChangingFragment qFragment :mActivity.mFragments) if(qFragment!=this) { ImageView fImageView = (ImageView) qFragment.FindviewById(R.id.*imageView*) Fragment.onChangePicture(fImageView); } } Затем нужно наследовать ваши классы фрагментов от этого абстрактного класса. И поменять формат вашего списка фрагментов в главной активности. Во первых он должен быть публичный, что бы сами фрагменты могли им пользоваться. А во вторых он будет типизированн соглассно нашему новому классу: class MainActivity... { ... Public List mFragments = new ArrayList<>(); ... И вот. Теперь нам не надо проверять при загрузке фрагментов ничего, смена картинок будет происходить в тот же момент, когда для этого было выполнено условие (нажатие картинки то есть. Если вы в функции нажатия конечно добавите соответствующую функцию) Upd. Прошу прощения за несколько мелких ошибок в моем коде, это они вызвали у вас часть вопросов. Сейчас все исправил. 1) В вашей активности место создания фрагментов теперь должно выглядеть так _fragments.add(FRAGMENT_ONE, new FirstFragment(this)); _fragments.add(FRAGMENT_TWO, new SecondFragment(this)); _fragments.add(FRAGMENT_THREE, new ThirdFragment(this)); Что бы ваши фрагменты могли принимать такой параметр, см. пункт 4 2) Вью в этом случае может быть фрагментом, как раз их мы и перебираем в цикле функции changePictureOnOtherFragment(). В коде выше я исправил все что бы работало. Вообще, когда вы переопределяете событие нажатия по вью, вы работаете с методом onClick(View view). И вот эта view, которую метод получает в параметрах, и есть ваша ImageView, если вы конечно назначили этот метод на прослушивание нажатий по картинке. То есть вам нужно сейчас в этом методе onClick(View view) дописать строчки ImageView imgView = (ImageView)view;//преобразование абстрактной вью к формату вью-картинки onChangePicture(imgView);//этот метод в моем классе я только переписал выше. 3) Это была моя ошибка, там просто буквы перепутались 4) Да, правильно. Обозначение классов ваших фрагментов теперь должно выглядеть так public class *FragmentName* extends PictureChangingFragment. И ещё им нужен новый формат конструктора: public *fragmentName*(MainActivity mActivity) { super(mActivity); ... }

Ответ 2



Просто перенеси ту конструкцию которая меняет картинки при загрузки из функции onCreate в onResume. Тогда каждый фрагмент будет менять картинку как раз перед своим отображением. Upd Раз не получается использовать по назначению onResome(), тогда делай все фрагменты экземплярами интерфейса PicturesChangeListener с одним методом onPictureChange(), и вызывай этот метод через for(PicturesChangeListener qFragment : твой список фрагментов) qFragment.onPictureChange();

Комментариев нет:

Отправить комментарий