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.
Related
I am trying to use this photo camera plugin cordova-plugin-camera-preview in an HTML hybrid application and it works, but I can not place the controls on the camera layer while I focus. However, they appear above the layer when I take the photo and the camera shows the preview. Does anyone know if there is any configuration that can make the buttons appear on the camera layer?
Finally I found the solution in this line in js/index.js
var app = {
startCameraAbove: function(){
CameraPreview.show();
CameraPreview.startCamera({x: 0, y: 0, width: window.screen.width, height:
window.screen.height, camera: "back", toBack: true, previewDrag: false, tapPhoto: true});
},
At the beginning of the js/index.js script we must place these values in toBack:true to keep the camera back completely (be careful, the HTML background can cover it, I recommend put background: transparent in CSS), it is also recommended change previewDrag: false to avoid unveiling the background.
Building out react-native-maps and trying to decide the pros and cons of using animateToRegion vs. animateCamera. In the past we've handled everything on a region basis.
Seems like region would be a better choice, as you won't have to worry about differences between elevation and zoom, while also having a more granular control of the exact region being displayed if needed.
Anyone have any thoughts or experiences that have led them to one or the other?
I just made this switch myself. I found that animateCamera() is more versatile and allows for cleaner syntax.
The biggest pro for animateCamera() is that you can do multiple animations from a single method call.
An example of centering to coords and turning the camera 180 degrees with animateCamera():
this.map.animateCamera({
center: {
latitude: 0,
longitude: 0,
},
heading: 180,
});
If you wanted to do the same thing with animateToRegion() you would need to call two methods:
this.map.animateToRegion({
latitude: 0,
longitude: 0,
});
this.map.animateCamera({
heading: 180,
});
Not as clean.
As of right now, a con for animateCamera() is that you don't seem to be able to pass a latitudeDelta and longitudeDelta into the center property like you can with region, specified here.
In short, if you don't need to use a latitudeDelta and longitudeDelta then animateCamera() is the way to go. If I had to speculate, I would say animateToRegion() is going to be deprecated like the other methods sometime in the future in favor of animateCamera().
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 having a stage with 1 layer, which has 100 kineticImage objects (and 100 images attached to them, of course). when I click on a kinetic image object, I wrote a very simple tween:
var growTween = new Kinetic.Tween({
node: that.kineticImage,
duration: 0.1,
scaleX: that.kineticImage.scaleX()+0.2,
scaleY: that.kineticImage.scaleY()+0.2
});
growTween.play();
You could see the entire example at:
http://trueicecold.no-ip.org/pumpkin/demo.html
so each image pressed will grow by 20% over 1/10 seconds... on desktop it works perfectly fine, but on android I get poor performance... 300ms delay between the touchstart and the actual execution, and the tween is only 1-2 frames...
could it be 100 images are too heavy for android to handle? I'm using Galaxy S3.
EDIT: I've also tried with 100 circles: http://trueicecold.no-ip.org/pumpkin/demo2.html with the same result...
Canvas on mobile is noticeably slower than canvas on a desktop.
And a library like KineticJS that empowers objects on the canvas will be noticeably slower than pure mobile canvas.
For better performance, try temporarily moving your tweening object on a separate layer.
myTweeningShape.moveTo( myTweenLayer );
Only that 1 object gets redrawn with every tween-step and the other 99 objects (on the other layer) don't have to be redrawn.
Then when the tween ends you can put that tweened object back on the main layer again.
You can add the onFinish function to your tween which will fire when the tween ends.
[Additional thoughts]
(1) Too many new Image()'s
Just load the pumpkin image once outside your Pumpkin "class" and use that 1 image as the image for each of your Kinetic.Image's. Don't load and save a new Image() inside each Pumpkin.
(2) Tweens are not destroyed and therefore are accumulating
The Kinetic.Tween does not automatically destroy itself after the tween plays, so tell each new tween to destroy itself after it plays:
var growTween = new Kinetic.Tween({
node: that.kineticImage,
duration: 0.1,
scaleX: that.kineticImage.scaleX()+0.2,
scaleY: that.kineticImage.scaleY()+0.2
onFinish:function(){ this.destroy(); }
});