While testing out an application on Android I noticed something funky going on. A double click event handler has been triggering without any double clicks occurring on that particular item.
Trying to isolate the issue I discovered that pretty much every chain of clicks rapid as a double click on regardless what two objects would cause the second click on the second object to register as a double click, when in fact it is just a single click.
Below is an example consisting of a row of 3 randomly colored rectangles, each one with a mouse area inside of it. The double click of each mouse area is rigged to set the parent rectangle's color to a different random color. Clicking rapidly two different rectangles under android triggers a double click and a color change for the second. This does not happen on Windows or Ubuntu Linux.
Window {
id: main
visible: true
width: 400
height: 400
title: qsTr("Hello World")
Row {
Rectangle {
width: main.width * .33
height: main.height
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
border.color: "black"
border.width: 2
MouseArea {
anchors.fill: parent
onDoubleClicked: parent.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
}
}
Rectangle {
width: main.width * .33
height: main.height
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
border.color: "black"
border.width: 2
MouseArea {
anchors.fill: parent
onDoubleClicked: parent.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
}
}
Rectangle {
width: main.width * .33
height: main.height
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
border.color: "black"
border.width: 2
MouseArea {
anchors.fill: parent
onDoubleClicked: parent.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
}
}
}
}
It looks as if the "previous click" or whatever property that's supposed to be used to detect double clicks is shared between different mouse areas instead of being per mouse area. The issue manifests in both Qt 5.7 and 5.7.1.
It definitely looks like my 10th discovered Qt bug this year, but I still feel like asking on the odd chance someone knows what's going on and how to fix it, because I need this fixed, and the Qt bugreport process is not speedy. So any ideas are more than welcome.
Until there is a better answer with an actual solution, it may be useful to know that it is possible to somewhat mitigate the devastating effect this issue has on user experience by reducing the global interval for double click detection.
By default it is the rather lethargic 500 msec. I found out that by reducing it to 250 msec helps to avoid over 90% of the incorrect double clicks:
QGuiApplication app(argc, argv);
app.styleHints()->setMouseDoubleClickInterval(250);
Additionally, there is a quick and hacky qml-only way to create a "fixed" copy of MouseArea:
// MArea.qml
Item {
id: main
property alias mouseX : ma.mouseX
property alias mouseY : ma.mouseY
property alias acceptedButtons: ma.acceptedButtons
// etc aliases
signal clicked(var mouse)
signal doubleClicked(var mouse)
// etc signals, function accessors
MouseArea {
id: ma
property real lClick : 0
anchors.fill: parent
onClicked: {
var nc = Date.now()
if ((nc - lClick) < 500) main.doubleClicked(mouse)
else main.clicked(mouse)
lClick = nc
}
}
}
This one actually works as intended and can be made almost entirely "plug and play" compatible with the original one.
Related
I am having an issue when I deploy a Qt application on Android. Basically, my application contains two QML items, grouped into a stacked widget. It is a very simple code, but I can't remove the bottom grey bar as shown here:
Fullscreen failure
And my main code is:
QtWebView::initialize();
QApplication a(argc, argv);
MainWindow w;
w.setWindowTitle("Speakers Discovery");
w.showFullScreen();
return a.exec();
With the instantiation of the widget inside the MainWindow constructor:
m_page = new QQuickWidget(this);
m_page->setSource(QUrl("qrc:/loading_page.qml"));
With the .QML of the object displayed:
Item {
width: Screen.width
height: Screen.height
visible: true
Rectangle
{
anchors.fill: parent
color: "black"
Image { source: "qrc:/bg.jpg"; fillMode: Image.Stretch; anchors.fill: parent; opacity: 0.4 }
}
}
I had the same issue on windows, but changing showFullScreen to showMaximized made the trick. Do you have any clues for Android ?
Regards,
Julien.
I'm trying to make a react-native scrollview with 3 (or more) elements where the element in the middle of the screen is always 1.75 times the normal element size, and while scrolling the size changes dynamically. Can I find when the element is in the center of screen if the size of the scrollview will be changing? Is it possible to do without some complicated mathematical approach?
I was trying putting conditions to all elements' styles but can't find a way to determine when the condition is met.
handleScroll(event) {
var x = event.nativeEvent.contentOffset.x;
var page = x / this.state.totalWidth;
this.setState({ position: page })
}
isElementFocused(start, stop) {
return (this.state.position >= start && this.state.position < stop);
}
Element:
<View style={styles.swipeBox,
{
backgroundColor: this.isElementFocused(1, 2) ? this.getColor(1) : colors.primary,
width: this.isElementFocused(1, 2) ? this.getWidth(1) : this.state.baseWidth,
height: this.isElementFocused(1, 2) ? this.getHeight(1) : this.state.baseHeight,
}}>
<Text>test</Text>
</View>
I think you want to use smoothScrollToPosition()
please visit https://www.programcreek.com/java-api-examples/?class=android.support.v7.widget.RecyclerView&method=smoothScrollToPosition
Anyone knows how to change the speed of the scroll animation in ScrollToAsync method for Xamarin.Forms.ScrollView control?
I'm developing an Android App with Xamarin Forms.
Thanks
Unfortunately, at the time of this writing, the ScrollToAsync speed is hardcoded to 1000 ms (at least for Android).
I was able to work around this by just animating the scroll myself:
Point point = scrollView.GetScrollPositionForElement(targetElement, ScrollToPosition.Start);
var animation = new Animation(
callback: y => scrollView.ScrollToAsync(point.X, y, animated: false),
start: scrollView.ScrollY,
end: point.Y - 6);
animation.Commit(
owner: this,
name: "Scroll",
length: 300,
easing: Easing.CubicIn);
And here's the documentation for animation.
Modified from Taylor Lafrinere's answer, here is the same snippet as a horizontal scroll animation:
Point point = scrollView.GetScrollPositionForElement(screenContent, ScrollToPosition.Start);
// insert fix for iOS jumping here
var animation = new Animation(
callback: x => scrollView.ScrollToAsync(x, point.Y, animated: false),
start: scrollView.ScrollX,
end: point.X);
animation.Commit(
owner: this,
name: "Scroll",
length: 300,
easing: Easing.CubicIn);
It is worth pointing out that on iOS, this code displaced the view also towards the top. Something which you do not want. I believe the reason for this is that iOS understands the input for the animation as the lower edge of the scrollview whereas Android understands it as the upper edge of the scrollview.
To avoid this jump, set point.Y to 0 on iOS:
// iOS seems to understand the input for the animation as the lower edge of the scrollview
// Android the upper edge.
if (Xamarin.Forms.Device.RuntimePlatform == Xamarin.Forms.Device.iOS)
{
point.Y = 0;
}
I still think this answer should have been an edit, but since it was rejected as "Should be an answer or a comment" and it certainly cannot be a comment, here it is as an answer. The intent is to make it more clear that Taylor's Answer covers the vertical animation, and to show how to do a horizontal one instead.
To simulate the increase of speed of AsyncToScroll I've used the FadeTo method of scrollview and set the parameter "animated" of AsyncToScroll to false. (My example is for an horizontal scrollview)
await MyScrollView.FadeTo(1, 200, Easing.CubicIn);
await MyScrollView.ScrollToAsync(_newScrollX_value, 0, false);
I have a NativeScript project which contains a ListView. I used its event "onItemTap" and this is the function I wrote:
onItemTap(args){
let clicked = args.view.bindingContext;
let fav = this.page.getViewById("star-"+clicked.id);
fav.animate({
rotate: 360,
duration: 1000
});
}
Basically I'm retrieving the item I clicked, inside the item there is a label which has the id "star-N" [N is the intex of the item] and I'm animating it.
It works fine, the problem is that it just works once! From the second tap, it animates no more. The console isn't returning any errors. I'm using my Android device to debug it.
Any idea? Thanks!
Apparently after the rotation, the "rotate" property of the element isn't reset to its initial value. This means that in the first tap your rotate property goes from 0 => 360 and then on the second tap from 360 => 360 so no animation occurs.
Not sure if it is really intended to be like this but you can always manually set the rotate property to 0 once the animation is done:
onItemTap(args) {
let clicked = args.view.bindingContext;
let fav = this.page.getViewById("star-"+clicked.id);
fav.animate({
rotate: 360,
duration: 1000
}).then(() => fav.rotate = 0);
}
I'm using Nativescript 1.6 and this component https://github.com/bradmartin/nativescript-floatingactionbutton
I would like to have some nice "material design effect" when you click on this button and then navigate to another page. It's a bit hacky but it does the job and looks quite nice (i probably should use fragment transitions with shared elements when i was in native Android world, but im not)
My current attempt:
XML:
<FAB:fab tap="tap"
loaded="buttonLoaded"
row="1"
icon="res://ic_add_white_24dp"
rippleColor="#f1f1f1"
class="fab-button" />
JS:
fabButton.icon = ""; // Error! ResourceNotFoundException
fabButton.animate({
scale: { x: 20, y: 20 },
translate: { x: -200, y: -200 },
duration: 300
}).then(function(){
navigation.goToDetailPage();
fabButton.animate({ // reset button to original state
scale: { x: 1, y: 1 },
translate: { x: 0, y: 0 },
delay: 100,
duration: 0
});
});
2 questions:
How can i remove the icon, just for a nicer effect? "", {}, null are not allowed, should i really create a transparent png for this?
Is there a better way to restore/reset element after an animation?
If the exception is ResourceNotFoundException that looks like a native exception thrown so it doesn't look like you'll be able to set a null value. Your best option is probably an empty .png. I suppose the plugin could check for a null value and bypass the native exception but for now that's not the case. You could make a PR with this feature if you wanted.
As for resetting an element to its original state, what you are doing is what I would do. I don't think there would be a "better" way because once you've changed the state with the initial animation, the native setTranslateX/Y and other methods to run the animation have changed the items location/position/color, etc. So what you are doing is probably the best approach.
I'd like to see this animation if you don't mind, looks like something other devs might want :) Maybe record a .gif and attach here for others to see as a reference. If you don't have a tool to record a .gif here is what I use: http://www.cockos.com/licecap/ when I record from the emulators.
Hope this helps some.