Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Swipe gestures with QML Stackview
Forum Updated to NodeBB v4.3 + New Features

Swipe gestures with QML Stackview

Scheduled Pinned Locked Moved Solved QML and Qt Quick
8 Posts 2 Posters 5.1k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    daljit97
    wrote on last edited by
    #1

    So QML StackView provides a way to navigate back by usin the pop() function. I am looking for a way to go the previous page by simply swiping to the right with UI elements following the fingers of the user (kind of like a SwipeView). How can I achieve this? I have looked around and all I found was this https://github.com/alejoasotelo/SwipePageStackWindow which is an old project that does a similar thing with the old PageStack.
    I think the SwipeView is not really an alternative since my apps would contain at least 20 layers of "pages" so I would manually create and destroy the items to avoid performance issues. I thought about using a MouseArea and implement the gesture myself, but what I want the previous "page" to slide from the left as the user is swiping away the current item to the right. I don't understand how can get the previous "page" to do that. Does StackView provides a way to do that?

    raven-worxR 1 Reply Last reply
    0
    • D Offline
      D Offline
      daljit97
      wrote on last edited by daljit97
      #6

      @raven-worx said in Swipe gestures with QML Stackview:

      Thats the nature of a stack view

      Yeah I think that is the default behaviour, but I think I found a workaround. In the documentation, it is mentioned:

      By default, StackView shows incoming items when the enter transition begins, and hides outgoing items when the exit transition ends. Setting this property explicitly allows the default behavior to be overridden, making it possible to keep items that are below the top-most item visible.

      Then I was able to use that property to make the animation correctly. I believe that Qt Quick should have a default behaviour (it is such a common UI pattern nowadays) to achieve this as it is trivial to do and already built in the native development tools for Android and iOS.
      Anyway here is the working code:

          StackView{
              id: stack
      
              width: window.width
              height: window.height
              initialItem: initialComp
      
              pushEnter: Transition {
                  id: pushEnter
                  ParallelAnimation {
                      NumberAnimation { property: "x"; from: window.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
                      NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 400; easing.type: Easing.OutCubic }
                  }
              }
              pushExit: Transition {
                  id: pushExit
                  PropertyAction { property: "x"; value: pushExit.ViewTransition.item.pos }
                  PropertyAction { property: "y"; value: pushExit.ViewTransition.item.pos }
              }
              popEnter: Transition {
                  id: popEnter
                  PropertyAction { property: "x"; value: popEnter.ViewTransition.item.pos }
                  PropertyAction { property: "y"; value: popEnter.ViewTransition.item.pos }
              }
          }
          Component{
              id: initialComp
              Rectangle{
                  color: "purple"
                  width: window.width
                  height: window.height
                  StackView.visible: true
                  MouseArea{
                      anchors.fill: parent
                      onClicked: {
                          stack.push(pushComponent)
                      }
                  }
              }
          }
      
          Component{
              id: pushComponent
              SwipeView{
                  id: swipeView
                  currentIndex: 1
                  Connections{
                      target: swipeView.contentItem
                      onMovementEnded:{
                          if(swipeView.currentIndex == 0)
                          {
                              stack.pop()
                              console.log("popped")
                          }
                      }
                  }
      
                  Rectangle{
                      width: window.width
                      height: window.height
                      color: "transparent"
                  }
                  Rectangle{
                      width: window.width
                      color: "green"
                  }
              }
          }
      

      Why do you expect performance issues?

      Well I supposed I could make an implementation that is just as fast as the default StackView, but the documentation mentions:

      It is generally not advisable to add excessive amounts of pages to a SwipeView.

      I would also have to implement quite a lot of the functionality from StackView (like animations), so I am quite happy with this "hack".

      raven-worxR 1 Reply Last reply
      0
      • D daljit97

        So QML StackView provides a way to navigate back by usin the pop() function. I am looking for a way to go the previous page by simply swiping to the right with UI elements following the fingers of the user (kind of like a SwipeView). How can I achieve this? I have looked around and all I found was this https://github.com/alejoasotelo/SwipePageStackWindow which is an old project that does a similar thing with the old PageStack.
        I think the SwipeView is not really an alternative since my apps would contain at least 20 layers of "pages" so I would manually create and destroy the items to avoid performance issues. I thought about using a MouseArea and implement the gesture myself, but what I want the previous "page" to slide from the left as the user is swiping away the current item to the right. I don't understand how can get the previous "page" to do that. Does StackView provides a way to do that?

        raven-worxR Offline
        raven-worxR Offline
        raven-worx
        Moderators
        wrote on last edited by
        #2

        @daljit97
        you can use a listview. but anyway if you would "slide" to the last page in a stack view you would also have 20 items in the memory.

        Alternatively you could lay a swipe view over the stack view and make sure you only have 2 items in the stack view by doing the push/pop calls yourself appropriately.

        --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
        If you have a question please use the forum so others can benefit from the solution in the future

        D 1 Reply Last reply
        1
        • raven-worxR raven-worx

          @daljit97
          you can use a listview. but anyway if you would "slide" to the last page in a stack view you would also have 20 items in the memory.

          Alternatively you could lay a swipe view over the stack view and make sure you only have 2 items in the stack view by doing the push/pop calls yourself appropriately.

          D Offline
          D Offline
          daljit97
          wrote on last edited by
          #3

          Alternatively you could lay a swipe view over the stack view and make sure you only have 2 items in the stack view by doing the push/pop calls yourself appropriately.

          Could you explain that a little bit more?

          1 Reply Last reply
          0
          • D Offline
            D Offline
            daljit97
            wrote on last edited by
            #4

            So this is what I could come up with. I created a SwipeView which has an empty item and the actual content (left and right respectively), then when the StackView "pushes" to this SwipeView, the user is able to swipe to go back. The only problem is that the content "before" does not become visible until StackView::pop() doesn't get called. Is there anyway around this? Here is my code:

              StackView{
                    id: stack
                    anchors.fill: parent
                    initialItem: initialComp
            
                }
                Component{
                    id: initialComp
                    Rectangle{
                        color: "purple"
                        anchors.fill: parent
                        MouseArea{
                            anchors.fill: parent
                            onClicked: {
                                stack.push(pushComponent)
                            }
                        }
                    }
                }
            
                Component{
                    id: pushComponent
                    SwipeView{
                        id: swipeView
                        currentIndex: 1
                        Connections{
                            target: swipeView.contentItem
                            onContentXChanged: {
                                swipeView.opacity = swipeView.contentItem.contentX/swipeView.contentItem.contentWidth
                            }
                            onMovementEnded:{
                                if(swipeView.currentIndex == 0)
                                {
                                    stack.pop()
                                }
                            }
                        }
            
                        Rectangle{
                            width: window.width
                            height: window.height
                            color: "transparent"
                            onXChanged: console.log("x changed")
                        }
                        Rectangle{
                            width: window.width
                            color: "green"
                        }
            //            onCurrentIndexChanged: if(currentIndex == 0) stack.pop()
                    }
                }
            
            raven-worxR 1 Reply Last reply
            0
            • D daljit97

              So this is what I could come up with. I created a SwipeView which has an empty item and the actual content (left and right respectively), then when the StackView "pushes" to this SwipeView, the user is able to swipe to go back. The only problem is that the content "before" does not become visible until StackView::pop() doesn't get called. Is there anyway around this? Here is my code:

                StackView{
                      id: stack
                      anchors.fill: parent
                      initialItem: initialComp
              
                  }
                  Component{
                      id: initialComp
                      Rectangle{
                          color: "purple"
                          anchors.fill: parent
                          MouseArea{
                              anchors.fill: parent
                              onClicked: {
                                  stack.push(pushComponent)
                              }
                          }
                      }
                  }
              
                  Component{
                      id: pushComponent
                      SwipeView{
                          id: swipeView
                          currentIndex: 1
                          Connections{
                              target: swipeView.contentItem
                              onContentXChanged: {
                                  swipeView.opacity = swipeView.contentItem.contentX/swipeView.contentItem.contentWidth
                              }
                              onMovementEnded:{
                                  if(swipeView.currentIndex == 0)
                                  {
                                      stack.pop()
                                  }
                              }
                          }
              
                          Rectangle{
                              width: window.width
                              height: window.height
                              color: "transparent"
                              onXChanged: console.log("x changed")
                          }
                          Rectangle{
                              width: window.width
                              color: "green"
                          }
              //            onCurrentIndexChanged: if(currentIndex == 0) stack.pop()
                      }
                  }
              
              raven-worxR Offline
              raven-worxR Offline
              raven-worx
              Moderators
              wrote on last edited by
              #5

              @daljit97

              The only problem is that the content "before" does not become visible until StackView::pop() doesn't get called. Is there anyway around this?

              Thats the nature of a stack view

              @daljit97 said in Swipe gestures with QML Stackview:

              I think the SwipeView is not really an alternative since my apps would contain at least 20 layers of "pages" so I would manually create and destroy the items to avoid performance issues

              Why do you expect performance issues?

              --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
              If you have a question please use the forum so others can benefit from the solution in the future

              1 Reply Last reply
              0
              • D Offline
                D Offline
                daljit97
                wrote on last edited by daljit97
                #6

                @raven-worx said in Swipe gestures with QML Stackview:

                Thats the nature of a stack view

                Yeah I think that is the default behaviour, but I think I found a workaround. In the documentation, it is mentioned:

                By default, StackView shows incoming items when the enter transition begins, and hides outgoing items when the exit transition ends. Setting this property explicitly allows the default behavior to be overridden, making it possible to keep items that are below the top-most item visible.

                Then I was able to use that property to make the animation correctly. I believe that Qt Quick should have a default behaviour (it is such a common UI pattern nowadays) to achieve this as it is trivial to do and already built in the native development tools for Android and iOS.
                Anyway here is the working code:

                    StackView{
                        id: stack
                
                        width: window.width
                        height: window.height
                        initialItem: initialComp
                
                        pushEnter: Transition {
                            id: pushEnter
                            ParallelAnimation {
                                NumberAnimation { property: "x"; from: window.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
                                NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 400; easing.type: Easing.OutCubic }
                            }
                        }
                        pushExit: Transition {
                            id: pushExit
                            PropertyAction { property: "x"; value: pushExit.ViewTransition.item.pos }
                            PropertyAction { property: "y"; value: pushExit.ViewTransition.item.pos }
                        }
                        popEnter: Transition {
                            id: popEnter
                            PropertyAction { property: "x"; value: popEnter.ViewTransition.item.pos }
                            PropertyAction { property: "y"; value: popEnter.ViewTransition.item.pos }
                        }
                    }
                    Component{
                        id: initialComp
                        Rectangle{
                            color: "purple"
                            width: window.width
                            height: window.height
                            StackView.visible: true
                            MouseArea{
                                anchors.fill: parent
                                onClicked: {
                                    stack.push(pushComponent)
                                }
                            }
                        }
                    }
                
                    Component{
                        id: pushComponent
                        SwipeView{
                            id: swipeView
                            currentIndex: 1
                            Connections{
                                target: swipeView.contentItem
                                onMovementEnded:{
                                    if(swipeView.currentIndex == 0)
                                    {
                                        stack.pop()
                                        console.log("popped")
                                    }
                                }
                            }
                
                            Rectangle{
                                width: window.width
                                height: window.height
                                color: "transparent"
                            }
                            Rectangle{
                                width: window.width
                                color: "green"
                            }
                        }
                    }
                

                Why do you expect performance issues?

                Well I supposed I could make an implementation that is just as fast as the default StackView, but the documentation mentions:

                It is generally not advisable to add excessive amounts of pages to a SwipeView.

                I would also have to implement quite a lot of the functionality from StackView (like animations), so I am quite happy with this "hack".

                raven-worxR 1 Reply Last reply
                0
                • D daljit97

                  @raven-worx said in Swipe gestures with QML Stackview:

                  Thats the nature of a stack view

                  Yeah I think that is the default behaviour, but I think I found a workaround. In the documentation, it is mentioned:

                  By default, StackView shows incoming items when the enter transition begins, and hides outgoing items when the exit transition ends. Setting this property explicitly allows the default behavior to be overridden, making it possible to keep items that are below the top-most item visible.

                  Then I was able to use that property to make the animation correctly. I believe that Qt Quick should have a default behaviour (it is such a common UI pattern nowadays) to achieve this as it is trivial to do and already built in the native development tools for Android and iOS.
                  Anyway here is the working code:

                      StackView{
                          id: stack
                  
                          width: window.width
                          height: window.height
                          initialItem: initialComp
                  
                          pushEnter: Transition {
                              id: pushEnter
                              ParallelAnimation {
                                  NumberAnimation { property: "x"; from: window.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
                                  NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 400; easing.type: Easing.OutCubic }
                              }
                          }
                          pushExit: Transition {
                              id: pushExit
                              PropertyAction { property: "x"; value: pushExit.ViewTransition.item.pos }
                              PropertyAction { property: "y"; value: pushExit.ViewTransition.item.pos }
                          }
                          popEnter: Transition {
                              id: popEnter
                              PropertyAction { property: "x"; value: popEnter.ViewTransition.item.pos }
                              PropertyAction { property: "y"; value: popEnter.ViewTransition.item.pos }
                          }
                      }
                      Component{
                          id: initialComp
                          Rectangle{
                              color: "purple"
                              width: window.width
                              height: window.height
                              StackView.visible: true
                              MouseArea{
                                  anchors.fill: parent
                                  onClicked: {
                                      stack.push(pushComponent)
                                  }
                              }
                          }
                      }
                  
                      Component{
                          id: pushComponent
                          SwipeView{
                              id: swipeView
                              currentIndex: 1
                              Connections{
                                  target: swipeView.contentItem
                                  onMovementEnded:{
                                      if(swipeView.currentIndex == 0)
                                      {
                                          stack.pop()
                                          console.log("popped")
                                      }
                                  }
                              }
                  
                              Rectangle{
                                  width: window.width
                                  height: window.height
                                  color: "transparent"
                              }
                              Rectangle{
                                  width: window.width
                                  color: "green"
                              }
                          }
                      }
                  

                  Why do you expect performance issues?

                  Well I supposed I could make an implementation that is just as fast as the default StackView, but the documentation mentions:

                  It is generally not advisable to add excessive amounts of pages to a SwipeView.

                  I would also have to implement quite a lot of the functionality from StackView (like animations), so I am quite happy with this "hack".

                  raven-worxR Offline
                  raven-worxR Offline
                  raven-worx
                  Moderators
                  wrote on last edited by
                  #7

                  @daljit97 said in Swipe gestures with QML Stackview:

                  I believe that Qt Quick should have a default behaviour (and such a common UI pattern nowadays)

                  it has... but you just dont like it... like you already mentioned in your first post

                  @daljit97 said in Swipe gestures with QML Stackview:

                  Well I supposed I could make an implementation that is just as fast as the default StackView, but the documentation mentions:

                  It is generally not advisable to add excessive amounts of pages to a SwipeView.

                  20 pages are not "excessive", unless they do not show some overloaded pages with tens to hundreds(?) items each.

                  But you could have simply tried it and check if there are any performance considerations at all

                  --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                  If you have a question please use the forum so others can benefit from the solution in the future

                  D 1 Reply Last reply
                  0
                  • raven-worxR raven-worx

                    @daljit97 said in Swipe gestures with QML Stackview:

                    I believe that Qt Quick should have a default behaviour (and such a common UI pattern nowadays)

                    it has... but you just dont like it... like you already mentioned in your first post

                    @daljit97 said in Swipe gestures with QML Stackview:

                    Well I supposed I could make an implementation that is just as fast as the default StackView, but the documentation mentions:

                    It is generally not advisable to add excessive amounts of pages to a SwipeView.

                    20 pages are not "excessive", unless they do not show some overloaded pages with tens to hundreds(?) items each.

                    But you could have simply tried it and check if there are any performance considerations at all

                    D Offline
                    D Offline
                    daljit97
                    wrote on last edited by daljit97
                    #8

                    @raven-worx said in Swipe gestures with QML Stackview:

                    @daljit97 said in Swipe gestures with QML Stackview:

                    I believe that Qt Quick should have a default behaviour (and such a common UI pattern nowadays)

                    it has... but you just dont like it... like you already mentioned in your first post

                    @daljit97 said in Swipe gestures with QML Stackview:

                    Well I supposed I could make an implementation that is just as fast as the default StackView, but the documentation mentions:

                    It is generally not advisable to add excessive amounts of pages to a SwipeView.

                    20 pages are not "excessive", unless they do not show some overloaded pages with tens to hundreds(?) items each.

                    But you could have simply tried it and check if there are any performance considerations at all

                    No, the default behaviour needs to be changed or an option needs to be added because on mobile platforms the use of buttons to go back is cumbersome (it is acceptable for Android, but for iOS a gesture based implementation is definitely needed). There is a big need for Qt developers to implement this and I am sure that many people find it odd that Qt hasn't got this. Few people have already asked for something similar to what I asked, for example look here:
                    https://forum.qt.io/topic/72499/ios-app-in-qml-how-to-navigate-backward-through-stackview-via-swipe-gestures
                    https://forum.qt.io/topic/56296/stackview-pop-a-page-by-swiping

                    As for SwipeView , I haven't gone through that route because I have some WebView in some of the pages and thought that could affect performance. I suppose you are right that I could have tested that, but I also needed some functionalities provided by StackView which I would have had to reimplement.

                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved