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);
}
Related
I am having this strange issue when I try to set the pitch, heading, bounds and centerCoordinate of a camera in a single config.
Initially, this is the config of the camera I am having -
pitch: 0
heading: 0
bounds: some coordinate bounds
centerCoordinate: null
These values are passed to the camera via props as follows -
const {
followUserLocation,
heading,
pitch,
animationDuration,
zoomLevel,
centerCoordinate,
bounds
} = this.state;
<MapboxGL.Camera
ref={camera => (this._camera = camera)}
bounds={bounds}
centerCoordinate={centerCoordinate}
heading={heading}
pitch={pitch}
animationDuration={animationDuration}
zoomLevel={zoomLevel}
followUserLocation={locationPermissionGranted ?
followUserLocation : false}
followUserMode={'normal'}
/>
On certain external event, I receive set of waypoints and I want to update the pitch and heading as well as focus the camera on each of the waypoints per external event (like next/prev button click). So I do following -
this.setState({
pitch: 60,
heading: someHeading,
animationDuration: 400,
bounds: undefined,
centerCoordinate: nextWaypoint,
zoomLevel
})
and my camera properly updates the pitch, heading, removes the default bounds and focuses to the centerCoordinate all at once properly.
Problem occurs when I try to 'reset' the camera to the default stage - reset pitch, heading, clear the centerCoordinate and set some bounds using setState -
this.setState({
heading: 0, //reset
pitch: 0, //reset
animationDuration: 1000,
bounds : defaultBounds,
centerCoordinate: null, //reset
zoomLevel: undefined // reset
})
When I do that, the camera is not properly reset to the default position - pitch and heading is not reset (takes the old ones) and bounds are also not properly set.
When I try to set the pitch and heading first, add some timeout and then set the bounds, it works, but not in single go. Am I doing something wrong or is this a known bug?
I am doing all this when the mapbox has finished loading, i.e, when the onDidFinishLoadingMap event is triggered.
I also tried using setCamera(cameraConfig) function instead of state approach, but got the same results.
Platform: Android, IOS
Version: 7.0.0-rc3
RN version - 0.59.10
I have two ImageView(s) set in my layout one on top of the other, say A and B.
I have set the alpha of B to 0 so it's totally faded as I want to control which image is displayed by setting the appropriate alpha to 1 in my code.
Now I also want to rotate the Images by 360 degrees before they fade out and before the new image comes on the screen when I click on the ImageView(s).
I'm using the ViewPropertyAnimator's rotation() and alpha() methods to do this.
This works without any issues when the App is installed and runs for for 1st time.
However, next time when I click on the Images, only the fade-in and fade-out animations work.
The rotation does not work.
Check this code :
boolean isImage1Showing = true;
//onClick() method for the 2 ImageView(s)
public void fadeAndRotate(View view){
if (isImage1Showing){
//Rotate the resource on 1st ImageView by 360 degrees
imageViewA.animate().rotation(360f).setDuration(2000);
imageViewA.animate().alpha(0).setDuration(2000);
//Displaying the other image on to the screen
imageViewB.animate().alpha(1).setDuration(2000);
isImage1Showing = false;
} else {
isImage1Showing = true;
imageViewB.animate().rotation(360f).setDuration(2000);
//Displaying the previous image
imageViewA.animate().alpha(1).setDuration(2000);
//fading out the currently displayed image
imageViewB.animate().alpha(0).setDuration(2000);
}
}
Use the
.rotationBy(float value)
method instead of the
.rotation(float value)
method. In your case it rotates TO 360f but you want it to rotate BY 360f.
So this code should work :
imageViewA.animate().rotationBy(360f).setDuration(2000);
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);
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.
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.