Search code examples
javaandroidandroid-viewpager2

ViewPager2 flashes/reloads on swipe


I'm trying to build an Android application using the new ViewPager2. I've added two ViewPagers, separated by a view, and when you swipe, both viewpagers should move. Both view pagers are moving correctly but upon completion of the gesture, the swiped view flashes and the non swiped view reloads, as demonstrated by the attached gif. Here is my code for the Activity, ViewPagerAdapter, and Fragment. Any help is appreciated

enter image description here

    public class MainActivity extends FragmentActivity {

    ActivityMainBinding viewBinding;

    MyPager adapter1, adapter2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        List<String> data = populateData();

        adapter1 = new MyPager(this, data);
        adapter2 = new MyPager(this, data);

        viewBinding.viewPager.setAdapter(adapter1);
        viewBinding.viewPager2.setAdapter(adapter2);

        viewBinding.viewPager2.setOffscreenPageLimit(data.size());
        viewBinding.viewPager.setOffscreenPageLimit(data.size());

        viewBinding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {

            @Override
            public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
                viewBinding.viewPager2.scrollTo(positionOffsetPixels, 0);
            }

            @Override
            public void onPageScrollStateChanged(final int state) {
                viewBinding.viewPager2.setCurrentItem(viewBinding.viewPager.getCurrentItem(), true);
            }
        });
        viewBinding.viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {

            @Override
            public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
                viewBinding.viewPager.scrollTo(positionOffsetPixels, 0);
            }

            @Override
            public void onPageScrollStateChanged(final int state) {
                viewBinding.viewPager.setCurrentItem(viewBinding.viewPager2.getCurrentItem(), true);
            }
        });

    }
    private List<String> populateData() {
        List<String> data = new ArrayList<>();
        for (int x = 0; x < 10; x++) {
            String derril = "derril " + x;
            data.add(derril);
        }
        return data;
    }
}
public class MyPager extends FragmentStateAdapter {

    List<String> data;

    public MyPager(@NonNull FragmentActivity fragmentActivity, List<String> data) {
        super(fragmentActivity);
        this.data = data;
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return DerrilFragment.newInstance(data.get(position));
    }

    @Override
    public int getItemCount() {
        return data.size();
    }
}
public class DerrilFragment extends Fragment {

    PizzaBinding viewBinding;

    String data;

    private DerrilFragment(String data) {
        this.data = data;
    }

    public static DerrilFragment newInstance(String data) {
        return new DerrilFragment(data);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        viewBinding = DataBindingUtil.inflate(inflater, R.layout.pizza, container, false);

        viewBinding.text.setText(data);

        return viewBinding.getRoot();

    }
}

Solution

  • You can implement by RecyclerView.

    class MainActivity : AppCompatActivity() {
        private var isFirstFocused = false
    
        private val helper: SnapHelper = LinearSnapHelper()
        private val helper2: SnapHelper = LinearSnapHelper()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            recycler1.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    super.onScrolled(recyclerView, dx, dy)
                    if (isFirstFocused) recycler2.scrollBy(dx, dy)
                }
            })
            recycler2.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    super.onScrolled(recyclerView, dx, dy)
                    if (!isFirstFocused) recycler1.scrollBy(dx, dy)
                }
            })
            recycler2.setOnTouchListener { v, event ->
                if (event.action  != null && event.action == MotionEvent.ACTION_DOWN ) {
                    isFirstFocused = false
                    return@setOnTouchListener  true
                }
                return@setOnTouchListener false
            }
            recycler1.setOnTouchListener { v, event ->
                if (event.action  != null && event.action == MotionEvent.ACTION_DOWN ) {
                    isFirstFocused = true
                    return@setOnTouchListener  true
                }
                return@setOnTouchListener false
            }
            helper.attachToRecyclerView(recycler1)
            helper2.attachToRecyclerView(recycler2)
            val manager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
            val manager2 = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
            recycler1.layoutManager = manager
            recycler2.layoutManager = manager2
            recycler2.adapter = Adapter(items)
            recycler1.adapter = Adapter(items)
        }
    
        private val items = listOf("One", "Two", "Three")
    
    }
    
    class Adapter(val list: List<String>) : RecyclerView.Adapter<Adapter.Holder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
            val view = LayoutInflater.from(parent.context).inflate(
                R.layout.activity_listview,
                parent,
                false
            )
            return Holder(view)
        }
    
        override fun onBindViewHolder(holder: Holder, position: Int) {
            holder.itemView.text_view.text = list[position]
        }
    
        override fun getItemCount() = list.size
    
        class Holder(view: View) : RecyclerView.ViewHolder(view)
    }