#java #android #android-viewpager2
#java #Android #android-viewpager2
Вопрос:
Я пытаюсь создать приложение для Android, используя новый ViewPager2. Я добавил две страницы просмотра, разделенные видом, и когда вы проводите пальцем, обе страницы просмотра должны перемещаться. Оба пейджера просмотра перемещаются правильно, но по завершении жеста мигает просмотренный вид, а не просмотренный вид перезагружается, как показано в прикрепленном gif. Вот мой код для Activity, ViewPagerAdapter и Fragment. Любая помощь приветствуется
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();
}
}
Комментарии:
1. Почему у вас есть 2 ViewPagers? Вам нужен только 1.
2. потому что страницы просмотра разделены представлением. если вы можете сделать это в одном viewpager, мне было бы интересно услышать, как
3. Похоже, что ваши ViewPagers находятся друг над другом. Так что для меня это не имеет смысла.
4. Что насчет этого не имеет смысла? Один ViewPager сверху, разделенный view, затем второй ViewPager.
Ответ №1:
Вы можете реализовать с помощью 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 amp;amp; event.action == MotionEvent.ACTION_DOWN ) {
isFirstFocused = false
return@setOnTouchListener true
}
return@setOnTouchListener false
}
recycler1.setOnTouchListener { v, event ->
if (event.action != null amp;amp; 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)
}
Ответ №2:
Вы можете попробовать использовать adapter.setOffscreenPageLimit = n
. Он устанавливает количество страниц, которые должны быть сохранены по обе стороны от текущей видимой страницы (страниц). Страницы, превышающие это ограничение, будут воссозданы из адаптера при необходимости, если у вас ограниченное количество страниц. Более подробная информация здесь.
Ответ №3:
В ваших setCurrentItem()
обычаях (в разделе onPageScrollStateChanged()
) установите для второго параметра значение false
Это отключит анимацию (не навсегда) в ViewPager при программной настройке страницы, поэтому вы видите анимацию, похожую на flash.
Чтобы знать, почему:
Рассмотрим два ViewPagers A и B
Вы прокручиваете страницу с одной страницы на другую в A, что вызывает ту же прокрутку в ViewPager
B. Как только вы полностью прокручиваете страницу с одной страницы на другую в A, значение currentItem
внутренне устанавливается A, но не для B.
Теперь вы сообщаете B об изменении страницы путем вызова setCurrentItem([index], true)
, который, независимо от вашей прокрутки, будет анимировать изменение страницы, вводящее flash (ваша индуцированная прокрутка сбрасывается в обычное состояние, и запускается анимация страницы для перехода с одной страницы на другую)
Ответ №4:
это выглядит немного подозрительно, что вы вызываете setCurrentItem
inside onPageScrollStateChanged
для каждого пройденного state
… попробуйте добавить некоторые if
и setCurrentItem
только тогда, когда state==ViewPager2.SCROLL_STATE_IDLE
список состояний:
ViewPager2.SCROLL_STATE_IDLE
ViewPager2.SCROLL_STATE_DRAGGING
ViewPager2.SCROLL_STATE_SETTLING
ViewPager2.SCROLL_STATE_DRAGGING
состояние обрабатывается в onPageScrolled
методе (совместное смещение позиции, иначе. перетаскивание пальцем)
ViewPager2.SCROLL_STATE_SETTLING
является ли автоматическая прокрутка (привязка) ViewPager2
к ближайшей странице — здесь я не уверен, что ViewPager2
перетаскивание «по коду» (совместное использование позиции с scrollTo
) также будет входить в это state
, вызывая такое же поведение привязки (так же onPageScrolled
?).)… стоит протестировать, добавить туда несколько журналов
также: вы перетаскиваете один ViewPager2
и onPageScrolled
вызываете scrollTo
второй ViewPager2
. это может привести к вызову onPageScrolled
call для этого второго прослушивателя, который вызывает первый ViewPager2
scrollTo
метод и так далее… зацикливается. рассмотрите возможность динамической отмены регистрации слушателя, когда пользователь начнет перетаскивать ViewPager2
его, и повторной регистрации при завершении движения ( SCROLL_STATE_IDLE
state
)
Ответ №5:
Я думаю, проблема в том, что в методе onPageScrolled для обоих ViewPagers вы прокручиваете другой пейджер. Таким образом, обе страницы могут прокручивать друг друга одновременно. Например, если вы прокручиваете ViewPager_1, то его метод onPageScrolled будет прокручивать ViewPager_2, а поскольку ViewPager_2 теперь прокручивается, будет вызван его метод onPageScrolled, который будет прокручивать ViewPager_1 и наоборот. Итак, вам может потребоваться рассмотреть возможность применения проверки, что если touch удерживается в ViewPager_1, то код внутри метода onPageScrolled ViewPager_2 не должен выполняться. Или, если вы хотите избежать этих проверок. Затем registerOnPageChangeCallback / unregisterOnPageChangeCallback вызывает прослушиватель другого ViewPager при удержании касания.
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
viewBinding.viewPager.scrollTo(positionOffsetPixels, 0);
}
Комментарии:
1. Проблема в том, что требование к этой функции заключается в том, что необходимо синхронизировать прокрутки между каждым viewpager