QML : Flippable issue - qt

I am trying to make a flippable clock in QML.
But am not able to get the flippable effect as desired, I have referred the documentation of flip method, took that as base for further development.
Tried various approaches but didn't succeed. Any idea how to get that effect.
Below is the referred documentation code snippet
import QtQuick 1.0
Flipable {
id: flipable
width: 240
height: 240
property bool flipped: false
front: Image { source: "front.png"; anchors.centerIn: parent }
back: Image { source: "back.png"; anchors.centerIn: parent }
transform: Rotation {
id: rotation
origin.x: flipable.width/2
origin.y: flipable.height/2
axis.x: 1; axis.y: 0; axis.z: 0 // set axis.x to 1 to rotate around y-axis
angle: 0 // the default angle
}
states: State {
name: "back"
PropertyChanges { target: rotation; angle: 180 }
when: flipable.flipped
}
transitions: Transition {
NumberAnimation { target: rotation; property: "angle"; duration: 4000 }
}
MouseArea {
anchors.fill: parent
onClicked: flipable.flipped = !flipable.flipped
}
}

You can't flip just half of an Item. To simulate a flip clock you have to use two clones of an image.
Try to add this at the end of the code above:
Item {
anchors {top: flipable.top; horizontalCenter: flipable.horizontalCenter}
width: flipable.width
height: flipable.height / 2
z: flipable.z + 1
clip: true
Image {
source: "front.png";
anchors.centerIn: parent
}
}
Obviously this code is not the solution, it's just a hint on what you have to do for the complete solution.

Related

Flipable overlapping other elements

In my QML application I'm trying to create a grid of items that can be flipped at the press of a button. The backside of such an item should then fill a major part of the screen until it is flipped back.
Let's say I start off with the following view of my application
When I press the question mark button of the item in the center then the item is flipped and moved slightly. What I would expect to see after this is the following
The blue box is the backside of my item and it covers most of the screen. Pressing the 'X'-Button on the top right would again flip the item back.
However what I actually see after flipping the first time is the following
You can see that parts of the items in my grid are covered by my flipped item and parts are not.
The code I'm using is as follows
import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2
import QtQuick.Window 2.2
Window {
id: main
width: 640
height: 480
visible: true
title: qsTr("Hello World")
function absolutePos(item) {
var my_x = item.x
var my_y = item.y
if (item.parent !== null) {
var parent_pos = absolutePos(item.parent)
my_x += parent_pos.x
my_y += parent_pos.y
}
return {x: my_x, y: my_y}
}
GridLayout {
columns: 5; rows: 3
Repeater {
model: 15
delegate: Item {
width: main.width / 5 - 10
height: main.height / 3 - 10
Flipable {
id: flipable
anchors.fill: parent
property bool flipped: false
front: Rectangle {
anchors.fill: parent
border.color: "black"
border.width: 2
}
back: Rectangle {
id: backSide
width: 580; height: 400
property var absolute_pos: absolutePos(this)
border.color: "blue"
border.width: 2
Button {
anchors.top: parent.top
anchors.right: parent.right
text: "X"
width: 30; height: 30
onClicked: {
flipable.flipped = !flipable.flipped
}
}
}
transform: [
Rotation {
id: rotation
origin.x: flipable.width / 2
origin.y: flipable.height / 2
axis.x: 0; axis.y: 1; axis.z: 0
angle: 0
},
Translate {
id: translation
x: 0; y: 0
}
]
states: State {
name: "back"
PropertyChanges {
target: rotation
angle: 180
}
PropertyChanges {
target: translation
x: 490 - backSide.absolute_pos.x
}
PropertyChanges {
target: translation
y: 40 - backSide.absolute_pos.y
}
when: flipable.flipped
}
transitions: Transition {
ParallelAnimation {
NumberAnimation {
target: rotation
property: "angle"; duration: 300
}
NumberAnimation {
target: translation
property: "x"; duration: 300
}
NumberAnimation {
target: translation
property: "y"; duration: 300
}
}
}
}
Button {
anchors.top: parent.top
anchors.right: parent.right
text: "?"
width: 30; height: 30
onClicked: {
flipable.flipped = !flipable.flipped
}
}
}
}
}
}
I was already trying to achieve the effect by manually setting the parent of my Flipable to Window.contentItem so that it will always be above any other items. However this also doesn't fix the problem since the item will still cover the siblings following the current item.
Also I'm still hoping, there is a solution which doesn't require manipulating the z-order of my items in some arcane way.
I am not sure what you mean by "some arcane way", but changing the z property of your delegate is perfectly fine:
delegate: Item {
z: flipable.flipped ? 1 : 0
// ...
}
You will also probably want to hide the "?" button when flipped:
visible: !flipable.flipped

ListView Load element with animation one by one

I have a simple ListView here with RotationAnimation when the listview is loaded. Basically the listview I have has pre defined model or list elements. I want to load each element with the RotationAnimation that I have one by one. For example, first element is displayed with animation and after few milliseconds (0.5ms) the next element will be displayed with animation. What I currently have right now is the whole listview will be displayed with animation including all the elements already. Is there anyway to do what I want?
This is what I currently have where the whole listview is displayed with animation
ListView {
width: 240; height: 320
model: ListModel {
ListElement{
name:"One"
}
ListElement{
name:"Two"
}
ListElement{
name:"Three"
}
}
delegate: Rectangle {
width: 100; height: 30
border.width: 1
color: "Transparent"
Text {
anchors.centerIn: parent
text: name
}
Component.onCompleted: seqAnim.start();
transform: Rotation { id:rotate; origin.x: width; origin.y: height; axis { x: 0.3; y: 1; z: 0 } angle: 0}
SequentialAnimation {
id: seqAnim
running: false
RotationAnimation { target: rotate; from: 180; to: 0; duration: 3000; easing.type: Easing.OutBack; property: "angle" }
}
}
}
What I want is the ListElements are displayed one by one entering from left to right
With a static model like you used, you will get all elements animated since that happens in the delegate.
On the other hand, with a dynamic model (where elements are added along the way), will let you get animation for each element individually.
You need to manage (suitably) how model elements are added to the model based on your practical model.
An example to demonstrate the concept is by adding model elements with a timer, sine you mentioned you want a period between the animations ...
ListModel {
id:lModel
ListElement{
name:"One"
}
}
Timer {
property int indexer: 0
id:timer
interval: 1000 ;running: true; repeat: true
onTriggered: {
if(indexer === 0)
lModel.append({name:"Two"})
else if (indexer === 1)
lModel.append({name:"Three"})
else timer.stop()
indexer++
}
}
ListView {
width: 240; height: 320
model: lModel
delegate: Rectangle {
width: 100; height: 30
border.width: 1
color: "Transparent"
Text {
anchors.centerIn: parent
text: name
}
Component.onCompleted: seqAnim.start();
transform: Rotation { id:rotate; origin.x: width; origin.y: height; axis { x: 0.3; y: 1; z: 0 } angle: 0}
SequentialAnimation {
id: seqAnim
running: false
RotationAnimation { target: rotate; from: 180; to: 0; duration: 3000; easing.type: Easing.OutBack; property: "angle" }
}
}
}

QML - Why do animations conflict?

Example of Qml - Flipable:
import QtQuick 2.0
Flipable {
id: flipable
width: 240
height: 240
property bool flipped: false
front: Rectangle { width: 200; height: 200; color: 'red'; anchors.centerIn: parent }
back: Rectangle { width: 200; height: 200; color: 'blue'; anchors.centerIn: parent }
transform: Rotation {
id: rotation
origin.x: flipable.width/2
origin.y: flipable.height/2
axis.x: 0; axis.y: 1; axis.z: 0 // set axis.y to 1 to rotate around y-axis
angle: 0 // the default angle
}
states: State {
name: "back"
PropertyChanges { target: rotation; angle: 180 }
when: flipable.flipped
}
transitions: Transition {
NumberAnimation { target: rotation; property: "angle"; duration: 4000 }
}
MouseArea {
anchors.fill: parent
onClicked: flipable.flipped = !flipable.flipped
}
}
This example is running good but, if I use this code, Flipable doesn't run:
MouseArea {
anchors.fill: parent
onClicked: {
flipable.flipped = true;
flipable.flipped = false;
}
}
I think the animation conflicts when I first make the flipped property is true then false. Whereas I want flipable open and then close.
The problem is that you set the property flipped back to false before the flip animation even started.
If you want the full open/close animation, you have to wait for the "open" animation to finish before starting the "close" animation:
transitions: Transition {
id: transition
onRunningChanged: {
if (!running && flipable.flipped) {
flipable.flipped = false;
}
}
NumberAnimation { target: rotation; property: "angle"; duration: 4000 }
}
MouseArea {
anchors.fill: parent
onClicked: {
if (!transition.running) {
flipable.flipped = true;
}
}
}

QML StackView custom transition

I have gone through the Qt docs :Qt StackView yet still I can't figure out what am I doing wrong, because my code should produce fade in/out animation but what I got is just an instant blink between content. I hope my description is sufficient and clear.
StackView {
id: stackView
anchors.fill: parent
delegate: StackViewDelegate {
function transitionFinished(properties)
{
properties.exitItem.opacity = 1
}
property Component pushTransition: StackViewTransition {
PropertyAnimation {
target: enterItem
property: "opacity"
from: 0
to: 1
duration: 10
}
PropertyAnimation {
target: exitItem
property: "opacity"
from: 1
to: 0
duration: 10
}
}
}
initialItem: Item {
width: parent.width
height: parent.height
ListView {
model: pageModel
anchors.fill: parent
delegate: AndroidDelegate {
text: title
onClicked: stackView.push(Qt.resolvedUrl(page))
}
}
}
}
I hit the same problem and asked their support - their example is wrong.
replace
property Component pushTransition: StackViewTransition {
with
pushTransition: StackViewTransition {
and it should work. pushTransition is actually a property on StackViewDelegate
I'm still trying to get the transitionFinished function to work becuase their example of that doesn't work either.
The duration of your animation is 10 milliseconds, or 1/100th of a second.
This is working for me:
Window {
id: mainWindowId
width: 1280
height: 800
StackView {
id: stackViewId
anchors.fill: parent
replaceEnter: Transition {
PropertyAnimation{
property: "opacity"
from: 0
to: 1
duration: 300
}
}
replaceExit: Transition {
PropertyAnimation{
property: "opacity"
from: 1
to: 0
duration: 250
}
}
initialItem: "yourStartingPage.qml"
}
}
And for changing views:
stackViewId.replace("yourOtherPage.qml")

How to write a number animation on the mouse button press event in QML?

import QtQuick 1.0
Rectangle
{
width: 100; height: 100
color: "red"
MouseArea
{
anchors.fill: parent
onPressed:
{
NumberAnimation
{
target: parent.x
to: 50;
duration: 1000
}
}
}
}
I expect this code to shift the x position of the rectangle on the button press event, but this does nothing.
Where am I going wrong?
You are defining an NumberAnimation in a signal handler, it's not going to work properly. Furthermore, NumberAnimation target should be an item, and here you are targeting a property of an item. Here is your code corrected :
import QtQuick 1.0
Rectangle
{
id: rect
width: 100; height: 100
color: "red"
MouseArea
{
anchors.fill: parent
onPressed:
{
animation.start()
}
NumberAnimation
{
id: animation
target: rect
property: "x"
to: 50;
duration: 1000
}
}
}
If your rectangle animation should revert when mouse is released, you would like to take benefit of a proper state definition, and animate property "x" at each state change (between default and "pressed" states. Here is a self contained example :
import QtQuick 1.0
Rectangle {
id: root
width: 360
height: 200
Rectangle
{
id: rect
width: 100; height: 100
color: "red"
MouseArea
{
id: mouse
anchors.fill: parent
}
states: [
State {
name: "pressed"
when: mouse.pressed
PropertyChanges {
target: rect
x: 50
}
}
]
Behavior on x {
NumberAnimation { duration: 1000 }
}
}
}
If you need more complex animation, define a proper Transition. A simple Behavior, here, is more readable I find.
Try this code:
import QtQuick 1.0
Rectangle
{
width: 100; height: 100
color: "red"
MouseArea {
anchors.fill: parent
onPressed: {
animation.start();
}
}
NumberAnimation on x {
id: animation
running: false
to: 50
duration: 1000
}
}
From docs:
NumberAnimation is a specialized PropertyAnimation that defines an animation to be applied when a numerical value changes.
So, you want not to animate on click, but you want to assign animation to x property of rectangle and start it on click.

Resources