This is an awful problem. On ios it is much easier.
For me this worked:
If you attach the background, so the pager, the swipe is completely normal. But if you attach a child of the current fragment, the swipe will be registered in the onTouch method of the child. Thats pretty basic right.
You cannot return false from the onTouch interface of the child, because you have to touch it vertically...
Solution: You create a SwipeListener for every child view that can be attached.
The SwipeListener can detect if you are swiping.
But that's not the plan. You have to check whether the user swiped vertically. If so you can get the offsetX. It is normally a very small amount, which depends on the scroll speed. You connect the offsetX from the SwipeListener with the fakeDragBy(float) of the viewPager.
The scroll from the child will be put on the viewPager scroll.
You connect onSwipe(...) with fakeDragBy(...).
Of course you have to calculate the amount of fakeDragBy but that is simple. Look up the documentary. docs
Tip: Call beginFakeDrag before dragging.
Example:
package com.exsent.app.act;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import com.exsent.app.R;
/**
* Created by Jim-Linus Valentin Ahrend on 3/26/21.
*
**/
public class EXAMPLE extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewPager2 vp2 = findViewById(R.id.viewPager);
RecyclerView.Adapter anyAdapter = /* your adapter */ null;
vp2.setAdapter(anyAdapter);
//so this is the basic background
//now goto the Adapter
}
void drag(int dx){
ViewPager2 vp2 = findViewById(R.id.viewPager);
vp2.beginFakeDrag();
vp2.fakeDragBy(dx);
}
static class MyExampleAdapter extends
RecyclerView.Adapter<MyExampleAdapter.ViewHolder>{
private EXAMPLE x;
MyExampleAdapter(EXAMPLE x){this.x = x;}
private GestureDetector detector;
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int
position) {
if(position == 0){
//gesture detector
this.detector = new GestureDetector(x, new
MyGestureListener());
RecyclerView recyclerView =
holder.itemView.findViewWithTag("recycler");
recyclerView.setOnTouchListener(new
View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return detector.onTouchEvent(event);
}
});
}
}
@Override
public int getItemCount() {
return 2;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
FrameLayout fragemntView = new FrameLayout(x);
fragemntView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
RecyclerView recyclerView = new RecyclerView(x);
recyclerView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
recyclerView.setTag("recycler");
fragemntView.addView(recyclerView);
return new ViewHolder(fragemntView);
}
static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
}
static class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
EXAMPLE e;
public MyGestureListener(EXAMPLE e){
this.e = e;
}
@Override
public boolean onDown(MotionEvent event) {
Log.d("TAG","onDown: ");
// don't return false here or else none of the other
// gestures will work
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.i("TAG", "onSingleTapConfirmed: ");
return true;
}
@Override
public void onLongPress(MotionEvent e) {
Log.i("TAG", "onLongPress: ");
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.i("TAG", "onDoubleTap: ");
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.i("TAG", "onScroll: ");
//drag
if(distanceX>distanceY){ //this condition should check if it is vertical or horizontal. you can define it better if you want.
e.drag(distanceX);
}
return true;
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent
event2,
float velocityX, float velocityY) {
Log.d("TAG", "onFling: ");
return true;
}
}
}
}