well hello dear viewers.
My situation :
I have a viewpager that lets my user swiping on left and right. I have a screen (a fragment), that I want to be completed by the user before he can swipe.
EDIT 4 : SOLUTION
As the ViewPager2 works like a RecyclerView, I have added a MutableList to my adapter :
var fragmentList = mutableListOf<Fragment>(
BasicInfoFragment.newInstance(
activity
),
BondsFragment.newInstance(
activity
),
...
At the beginning, there only are, in the list, the fragments displayed before the "locking". When my condition is fulfilled or satisfied, I add the next fragments to the adapter's list, so they are available for swiping
Below are old things that does not work :
What I have done :
I customized the viewpager to lock swiping when I want it to be locked (see my code), but it disables the both directions.
Ideally, I want to disable only left to right swiping : I want the user can swipe back (right to left). I just want to disable swiping forward (left to right).
I tried to implements a onTouchListener on my view pager to detect the swiping direction, but it only works when the ViewPager is unlocked.
Can you help me ?
Edit 3 : New problems
I have tried to implement the viewpager2, but now I got problems with the children Layout.
When I need to display a fragment into another fragment, I use an extension method that I wrote basing me on this : how-to-add-a-fragment-in-kotlin-way
It looks like that :
inline fun FragmentManager.doTransaction(func: FragmentTransaction.() -> Unit) {
Log.d(TAG, "doTransaction")
val fragmentTransaction = beginTransaction()
fragmentTransaction.func()
fragmentTransaction.commit()
}
fun AppCompatActivity.replaceFragment(frameId: Int, fragment: Fragment) {
Log.d(TAG, "replaceFragment")
supportFragmentManager.doTransaction { replace(frameId, fragment) }
}
So I have several fragment having things like this :
companion object : CustomCompanion() {
@JvmStatic
override fun newInstance(activity: Activity): IdealsFragment {
val fragment =
IdealsFragment(
activity
)
(activity as NewCharacterActivity).replaceFragment(
R.id.fragmentIdeals_container_ideals,
IdealsRecyclerViewFragment.newInstance(
activity
)
)
return fragment
}
}
The thing is that with the ViewPager2, I got a "no view found for id" exception.
I understood it was because I used the fragment manager instead of the ChildSupportFragmentManager, so I replaced the fragment manager by the good one, but now I have a crash for : "Fragment has not been attached yet.".
Once again, can you help me ?
Thanks so much !
Code :
/**
* Class "LockableViewPager" :
* Custom viewpager that allows or not to swipe between fragments.
**/
class LockableViewPager : ViewPager {
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
companion object {
private const val TAG = "LockableViewPager"
}
/**
* Is swiping enabled ?
*/
private var swipeEnabled = true
/**
* Intercept all touch screen motion events.
* Allows to watch events as they are dispatched, and
* take ownership of the current gesture at any point.
*
* @param event : The motion event being dispatched down the hierarchy.
* @return Return true to steal motion events from the children and have
* them dispatched to this ViewGroup through onTouchEvent().
* The current target will receive an ACTION_CANCEL event, and no further
* messages will be delivered here.
*/
override fun onTouchEvent(event: MotionEvent): Boolean {
return when (swipeEnabled) {
true -> super.onTouchEvent(event)
false -> // Do nothing.
return false
}
}
/**
* Implement this method to intercept all touch screen motion events. This
* allows you to watch events as they are dispatched to your children, and
* take ownership of the current gesture at any point.
*
* @param event : The motion event being dispatched down the hierarchy.
* @return Return true to steal motion events from the children and have
* them dispatched to this ViewGroup through onTouchEvent().
* The current target will receive an ACTION_CANCEL event, and no further
* messages will be delivered here.
*/
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return when (swipeEnabled) {
true -> super.onInterceptTouchEvent(event)
false -> swipeEnabled
}
}
/**
* Sets the swipeEnabled value to lock or unlock swiping
*/
fun setSwipeEnabled(swipeEnabled: Boolean) {
this.swipeEnabled = swipeEnabled
}
}
Edit 2 : Maybe the solution ?
I put a raw View to the bottom of the activity layout that contains the view pager :
<View
android:id="@+id/touch_layer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" />
I created an abstract class that implements the View.OnTouchListener :
abstract class OverlayTouchListener : View.OnTouchListener {
companion object{
private const val TAG = "OverlayTouchListener"
}
}
Deserialized the overlay view in my activity :
var touchLayer = this.findViewById<View>(R.id.touch_layer)
Added the OverlayTouchListener to the touchLayer :
touchLayer?.setOnTouchListener(object : OverlayTouchListener() {
/**
* Called when a touch event is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
*
* @param v The view the touch event has been dispatched to.
* @param event The MotionEvent object containing full information about
* the event.
* @return True if the listener has consumed the event, false otherwise.
*/
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
Log.d(TAG, "onTouch")
if(event != null){
// Check the swiping direction and ViewPager.isSwipeEnabled
viewPager?.setSwipeEnabled(true)
viewPager?.onTouchEvent(event)
}
return true
}
})
Now, i just have to check if swiping is enabled. If not, call the viewPager.onTouchEvent only if the swipe is from right to left.
It's a little bit tricky, so if you have any suggestion ...