ViewPager(2)双联动效果
为了满足伸手党的需求,先贴上代码
源码
BaseLinkPageChangeListener.java
public class BaseLinkPageChangeListener implements ViewPager.OnPageChangeListener {
private final ViewPager linkViewPager;
private final ViewPager selfViewPager;
private int marginX = 0;
public BaseLinkPageChangeListener(ViewPager selfViewPager,ViewPager linkViewPager){
this.linkViewPager = linkViewPager;
this.selfViewPager = selfViewPager;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//计算移动值
marginX = ((selfViewPager.getWidth() + selfViewPager.getPageMargin()) * position
+ positionOffsetPixels) * (linkViewPager.getWidth() + linkViewPager.getPageMargin()) /
(selfViewPager.getWidth() + selfViewPager.getPageMargin());
if (linkViewPager.getScrollX() != marginX) {
linkViewPager.scrollTo(marginX, 0);
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
Activity.java
public class ViewpagerActivity extends AppCompatActivity {
private ViewPager mViewpager1;
private ViewPager mViewpager2;
private ZoomOutPageTransformer zoomOutPageTransformer;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpage1);
initView();
}
private void initView() {
mViewpager1 = findViewById(R.id.viewpager1);
mViewpager2 = findViewById(R.id.viewpager2);
mViewpager1.setAdapter(new TopViewPgaerAdapter(this));
mViewpager2.setAdapter(new BottomViewPagerAdapter(this));
mViewpager1.setOffscreenPageLimit(5);
mViewpager2.setOffscreenPageLimit(5);
BaseLinkPageChangeListener baseLinkPageChangeListener = new BaseLinkPageChangeListener(mViewpager1, mViewpager2);
mViewpager1.addOnPageChangeListener(baseLinkPageChangeListener);
BaseLinkPageChangeListener baseLinkPageChangeListener1 = new BaseLinkPageChangeListener(mViewpager2, mViewpager1);
mViewpager2.addOnPageChangeListener(baseLinkPageChangeListener1);
}
private static class TopViewPgaerAdapter extends PagerAdapter {
private Context context;
public TopViewPgaerAdapter(Context context) {
this.context = context;
}
@Override
public int getCount() {
return 5;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
// 判断是不是同一个视图
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View inflate = LayoutInflater.from(context).inflate(R.layout.item_top, container, false);
container.addView(inflate);
return inflate;
}
}
private static class BottomViewPagerAdapter extends PagerAdapter {
private Context context;
public BottomViewPagerAdapter(Context context) {
this.context = context;
}
@Override
public int getCount() {
return 5;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
// 判断是不是同一个视图
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View inflate = LayoutInflater.from(context).inflate(R.layout.item_bottom, container, false);
container.addView(inflate);
return inflate;
}
}
}
activity_viewpager.xml
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".viewpageruse1.ViewpagerActivity"> android:id="@+id/viewpager1" android:layout_width="match_parent" android:layout_height="200dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> android:id="@+id/viewpager2" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="30dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@id/viewpager1" />
item_top.xml
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> android:layout_width="200dp" android:layout_height="200dp" android:background="@color/teal_200" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
item_bottom.xml
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="20dp"> android:layout_width="200dp" android:layout_height="200dp" android:background="@color/purple_500" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
分析
实现思路: 通过ViewPager的OnPageChangeListener监听回调的onPageScrolled(int position, float positionOffset, int positionOffsetPixels)方法来实现联动效果,关键代码如下:
selfViewPager.getWidth() + selfViewPager.getPageMargin() 偏移比例 (selfViewPager.getWidth() + selfViewPager.getPageMargin()) * position + positionOffsetPixels 表示当前手指触摸的ViewPager的总偏移距离 linkViewPager.getWidth() + linkViewPager.getPageMargin() 表示联动的ViewPager的大小
//计算移动值'
//
marginX = ((selfViewPager.getWidth() + selfViewPager.getPageMargin()) * position
+ positionOffsetPixels) * (linkViewPager.getWidth() + linkViewPager.getPageMargin()) /
(selfViewPager.getWidth() + selfViewPager.getPageMargin());
if (linkViewPager.getScrollX() != marginX) {
linkViewPager.scrollTo(marginX, 0);
}
测试 问题 问题产生原因分析 暂未找到原因 解决方案(先上代码)
activity_viewpager.xml
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:splitMotionEvents="false" tools:context=".viewpageruse1.Viewpager1Activity"> android:id="@+id/mLinear1" android:layout_width="300dp" android:layout_height="wrap_content" android:background="@color/purple_500" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"> android:id="@+id/viewpager1" android:layout_width="match_parent" android:layout_height="200dp" /> android:id="@+id/mLinear2" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@id/mLinear1"> android:id="@+id/viewpager2" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="30dp" />
MyLinearLayout.java
public class MyLinearLayout extends LinearLayout {
private MyLinearLayout otherLinearLayout;
public MyLinearLayout(Context context) {
super(context);
}
public MyLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public LinearLayout getOtherLinearLayout() {
return otherLinearLayout;
}
public void setOtherLinearLayout(MyLinearLayout otherLinearLayout) {
this.otherLinearLayout = otherLinearLayout;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (otherLinearLayout != null) {
otherLinearLayout.fakeTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
public void fakeTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
}
Activity.java
public class ViewPagerActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpage);
MyLinearLayout mLinear1 = findViewById(R.id.mLinear1);
MyLinearLayout mLinear2 = findViewById(R.id.mLinear2);
mLinear1.setOtherLinearLayout(mLinear2);
mLinear2.setOtherLinearLayout(mLinear1);
ViewPager mViewpager1 = findViewById(R.id.viewpager1);
ViewPager mViewpager2 = findViewById(R.id.viewpager2);
mViewpager1.setAdapter(new TopViewPgaerAdapter(this));
mViewpager2.setAdapter(new BottomViewPagerAdapter(this));
mViewpager1.setOffscreenPageLimit(5);
mViewpager2.setOffscreenPageLimit(5);
}
private static class TopViewPgaerAdapter extends PagerAdapter {
private Context context;
public TopViewPgaerAdapter(Context context) {
this.context = context;
}
@Override
public int getCount() {
return 5;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
// 判断是不是同一个视图
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View inflate = LayoutInflater.from(context).inflate(R.layout.item_top, container, false);
container.addView(inflate);
return inflate;
}
}
private static class BottomViewPagerAdapter extends PagerAdapter {
private Context context;
public BottomViewPagerAdapter(Context context) {
this.context = context;
}
@Override
public int getCount() {
return 5;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
// 判断是不是同一个视图
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View inflate = LayoutInflater.from(context).inflate(R.layout.item_parent, container, false);
container.addView(inflate);
return inflate;
}
}
}
问题: 使用上述代码虽然解决了联动问题,但是在多指滑动时会出现如下问题
解决方案:
禁用多指触控 android:splitMotionEvents="false"
关键代码:
public void setOtherLinearLayout(MyLinearLayout otherLinearLayout) {
this.otherLinearLayout = otherLinearLayout;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (otherLinearLayout != null) {
otherLinearLayout.fakeTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
public void fakeTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
}
可能连你页没有想到,竟然能使用这么少的代码的量解决了联动的问题,而且滑动起来还很丝滑,viewpager2也是使用这种方式来解决的,而且Viewpager2运行起来更加的丝滑,毫无违和感,这一切还得归功于享学课堂的Colin老师,目前网上大部分的教程在viewpager上实现双联动都是使用滑动监听回调和继承viewpager的方式来解决问题。自从加入了享学课堂,才两个多月老板就给涨了两千薪水,之前同事做不出来的功能,我参考享学课堂老师讲的都解决了,哈哈,以后我就要跟着Colin老师学习下去。
废话不多说,viewpager2实现双联动直接上代码
activity_viewpager2.xml
android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:layout_weight="1" android:layout_marginBottom="10dp"> android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" /> android:id="@+id/linearLayout2" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="10dp" android:layout_weight="1"> android:id="@+id/viewPager2" android:layout_width="match_parent" android:layout_height="match_parent" />
fragment_test.xml
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TestFragment"> android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:gravity="center" android:textSize="20dp" android:text="@string/hello_blank_fragment" />
ViewPager2Activity.java
public class ViewPager2Activity extends AppCompatActivity {
private List
private List
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager2 viewPager = findViewById(R.id.viewPager);
ViewPager2 viewPager2 = findViewById(R.id.viewPager2);
MyLinearLayout linearLayout1 = findViewById(R.id.linearLayout1);
MyLinearLayout linearLayout2 = findViewById(R.id.linearLayout2);
linearLayout1.setOtherLinearLayout(linearLayout2);
linearLayout2.setOtherLinearLayout(linearLayout1);
fragments.add( new OneFragment());
fragments.add( new TwoFragment());
fragments.add( new ThreeFragment());
fragments2.add( new OneFragment());
fragments2.add( new TwoFragment());
fragments2.add( new ThreeFragment());
viewPager.setAdapter(new ViewPagerAdapter(this,fragments));
viewPager2.setAdapter(new ViewPagerAdapter(this,fragments2));
}
}
ViewPagerAdapter.java
public class ViewPagerAdapter extends FragmentStateAdapter {
private final List
public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity, List
super(fragmentActivity);
this.fragments = fragments;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments == null ? 0 : fragments.size();
}
}
OneFragment.java
public class TestFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_test, container, false);
}
}
TwoFragment.java
public class TwoFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_test, container, false);
}
}
ThreeFragment.java
public class ThreeFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_test, container, false);
}
}
效果:
看到没,要多丝滑,就有多丝滑,而且viewpager和viewpager2都是可以通用的,简简单单的代码就实现了,这一切都得感谢享学课堂的Colin老师,他们有着丰富的Android开发经验和前沿的开发技术,此刻都是独一无二的技术,好了,不多说了,我得找老师学习高级技术去了,学到了再分享给大家
相关文章
发表评论