December 10, 2010

kyleplattner kyleplattner
Lab Rat
242 posts

[Solved] iOS Style Rearrange of Icons

Page  
1

Lets say I have several rectangles on a page arranged in a grid. I want to implement the iPhone/iPad feature where a user can click and hold on a rectangle, signal to the user that he can move them (iOS does squiggly movement), and then allow him to rearrange the icons while the other icons fill in around his movement. He also needs a button on the interface to stop the rearrange mode. Does this make sense?

How could I implement something like this in QML.

21 replies

December 10, 2010

disperso disperso
Ant Farmer
183 posts

What you are proposing is quite complicated to to begin with. I would start writing on paper a state machine of the basic states that are needed. The default state is easy, the “squiggly” state is entered when someone long-presses the MouseArea, and is the same but adds animations to the rectangles, and allows dragging of them, etc.

The next one is probably the harder. I have no idea on how to do it, since I haven’t played with dragging stuff.

December 10, 2010

kyleplattner kyleplattner
Lab Rat
242 posts

Appreciate your help, really need to get my mind around the element drag rearrange code… mind blown

December 11, 2010

xsacha xsacha
Lab Rat
517 posts

Isn’t this exactly what a GridView [doc.qt.nokia.com] does?
You can use an onPressAndHold [doc.qt.nokia.com] inside the delegate to wait for the users action and then reparent that item to move it.
The other items will slide in to position (you can use onRemove [doc.qt.nokia.com] signal).

 Signature 

- Sacha

December 11, 2010

Bradley Bradley
Lab Rat
314 posts

Is onLongPress the same as onPressAndHold?

 Signature 

Nokia Certified Qt Specialist.

December 11, 2010

xsacha xsacha
Lab Rat
517 posts

Oh yes, it would be :) Thanks.

 Signature 

- Sacha

December 11, 2010

Bradley Bradley
Lab Rat
314 posts

I guess that would just leave animating the squiggly state, which I assume could be done in the delegate.

xsacha, thanks for the update. And the links to the docs! :)

 Signature 

Nokia Certified Qt Specialist.

December 11, 2010

xsacha xsacha
Lab Rat
517 posts

Not quite sure what you mean by a ‘squiggle’. I assume you just mean some sort of animation related to ‘loading’ though.

I will show how I manage loading events. I use a rotating circle with different shades of black along the perimeter:

loading.png
http://goo.gl/SDG7T

Loading.qml

  1. import QtQuick 1.0
  2. Image {
  3.     id: loading; source: "images/loading.png"
  4.     NumberAnimation on rotation {
  5.         from: 0; to: 360; running: loading.visible == true; loops: Animation.Infinite; duration: 900
  6.     }
  7. }

You could just have the Loading item inside your delegate then:

  1. Loading { id: squiggle; width:36; height:36; visible: false }

There are a few ways to enable/disable the Loading element. One way is to use the onPressed signal to make the Loading element visible (visible = true) and onReleased to make it invisible (visible = false).

  1. onPressed: squiggle.visible = true
  2. onReleased: squiggle.visible = false

You would also make it invisible when the onPressAndHold enters though, as it will be reparented as that stage and not part of the GridView. Makes sense I think :).

 Signature 

- Sacha

December 11, 2010

Bradley Bradley
Lab Rat
314 posts

Squiggly refers to the slight rotation oscillation on the icons when in a moveable state. Here is a video [youtube.com]

 Signature 

Nokia Certified Qt Specialist.

December 11, 2010

xsacha xsacha
Lab Rat
517 posts

Oh, I see.
Not sure if the OP wants to replicate this effect exactly as it seems a bit silly and obvious copying if you used it.

However, to do this, you would have to make use of States.

  1. GridView {
  2.     id: view
  3.     ...
  4.     states: [
  5.         State {
  6.             name: "normal";
  7.             ...
  8.         },
  9.         State {
  10.             name: "squiggle";
  11.             ...
  12.         },
  13.     ]
  14. }

Inside the delegate you would use:

  1. onPressAndHold: {
  2.     // code mentioned above for reparenting item
  3.     ...
  4.     view.state="squiggle"
  5. }

Then you would have code within the delegate for the animation, as follows:

  1. Image {
  2.     id: icon;
  3.     source: modelImageUrl // derived from model
  4.     NumberAnimation on rotation {
  5.         from: -40; to: 40; running: view.state=="squiggle"; loops: Animation.Infinite; duration: 400
  6.     }
  7. }

I haven’t tested that rotation out but I assume it loops -40, 40, -40. 400ms per side. Which is what you would want.

 Signature 

- Sacha

December 11, 2010

kyleplattner kyleplattner
Lab Rat
242 posts

So has anyone confirmed that rearranging an item in the grid view will cause the items to rearrange.

December 11, 2010

xsacha xsacha
Lab Rat
517 posts

I can confirm this.

Where your model is:

  1. model: EventModel {id: listmodel}

You can remove the object from the grid using:
  1. listmodel.remove(index)

Or simply move it to the end of the grid while you re-parent it and assign it to a new object:
  1. listmodel.move(index, listmodel.count - 1, 1)

And the grid will automatically refit. Note: Use the onRemove signal to create a fancy animation to go with this. Or use Behaviour modifiers.

You can also use Flow [doc.qt.nokia.com] QML element as an alternative to GridView. It doesn’t support model/delegate but rather Loader’s and Qt.createObject’s. As there is no predefined order, the order is created only from what appears. So you can remove objects from the view and have them realign depending on visibility/opacity and position.

 Signature 

- Sacha

December 11, 2010

kyleplattner kyleplattner
Lab Rat
242 posts

I can’t wait to try this on Monday morning.

Here is another complexity: what if I have two different sizes of rectangles that need rearranging?

December 11, 2010

Bradley Bradley
Lab Rat
314 posts
kyleplattner wrote:
Here is another complexity: what if I have two different sizes of rectangles that need rearranging?

The GridView will still be a grid of identically sized areas. You’d have space around the smaller ones.

 Signature 

Nokia Certified Qt Specialist.

December 12, 2010

xsacha xsacha
Lab Rat
517 posts

They will certainly appear as different sizes. However, as Bradley says, the center of the rectangle will not change. There will just be more space around them.
You can change the spacing of the GridView by using cellHeight [doc.qt.nokia.com] and cellWidth [doc.qt.nokia.com] properties.

If you need variable spacing, perhaps you would prefer a Flow element.

 Signature 

- Sacha

December 13, 2010

kyleplattner kyleplattner
Lab Rat
242 posts

I will have to apologize but I started poking around and I cannot figure out the reparenting code. Here is how I have things setup:

  1. import Qt 4.7
  2.  
  3. Rectangle {
  4.     width: 640
  5.     height: 480
  6.     color: "#111111"
  7.  
  8.  
  9.  
  10.         Component {
  11.                id: widgetmodel
  12.                Item {
  13.                    width: grid.cellWidth; height: grid.cellHeight
  14.                    Column {
  15.                        anchors.fill: parent
  16.                        Image { source: portrait; anchors.horizontalCenter: parent.horizontalCenter }
  17.                        
  18.                    }
  19.                }
  20.            }
  21.  
  22.            GridView {
  23.                id: grid
  24.                x: 0
  25.                y: 0
  26.                width: 640
  27.                height: 480
  28.                anchors.fill: parent
  29.                cellWidth: 80; cellHeight: 80
  30.  
  31.                model: WidgetModel {}
  32.                delegate: widgetmodel
  33.                highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
  34.                focus: true
  35.  
  36.            }
  37.  
  38.            MouseArea {
  39.                id: mouse_area1
  40.                x: 0
  41.                y: 0
  42.                width: grid.width
  43.                height: grid.height
  44.                onPressAndHold: {
  45.  
  46.                    widgetmodel.move(index, listmodel.count - 1, 1)
  47.                }
  48.            }
  49. }

Page  
1

  ‹‹ currentItem and currentIndex for ListView      Stirring Qt Quick into the mix ››

You must log in to post a reply. Not a member yet? Register here!