Animate Layer Opacity with UIView.Animate - c#

I have 2 CALayers, each with an image. Both have an initial Opacity of 0.
I want to animate Layer1's Opacity to 1 over 1 second, starting straight away. Then after a delay of 0.5 seconds, I want to animate Layer2's Opacity to 1 over 1 second. These 2 layers sit on top of one another.
What I am trying to achieve is having the first image fade in, then while it is fading in, fade the second image over it.
But I cannot use UIView.Animate for some reason as it does not animate at all, just sets the values straight away.
UIView.Animate(1, 0, UIViewAnimationOptions.CurveEaseIn, () =>
{
backgroundLayer.Opacity = 1;
}, () => UIView.Animate(5, () =>
{
backgroundLayer2.Opacity = 1;
}));
Here is simply tried to run the animation straight after one another and it still just sets the values right away and there is no animation.

UIView animations are intended for animating UIView properties and don't seem to play well with CALayers. Using UIImageViews instead of CALayers would solve your problem (then you should use the imageView.alpha property instead of the layer.opacity property).
However, if you insist on using CALayers you can animate them with CABasicAnimation. The code below accomplishes the animation you described (note that this is Swift code, as I don't use Xamarin).
var animation1 = CABasicAnimation(keyPath: "opacity")
// Don't go back to the initial state after the animation.
animation1.fillMode = kCAFillModeForwards
animation1.removedOnCompletion = false
// Set the initial and final states of the animation.
animation1.fromValue = 0
animation1.toValue = 1
// Duration of the animation.
animation1.duration = 1.0
var animation2 = CABasicAnimation(keyPath: "opacity")
animation2.fillMode = kCAFillModeForwards
animation2.removedOnCompletion = false
animation2.fromValue = 0
animation2.toValue = 1
animation2.duration = 1.0
// Add a 0.5 second delay.
animation2.beginTime = CACurrentMediaTime() + 0.5
// Animate!
backgroundLayer.addAnimation(animation1, forKey: "opacity")
backgroundLayer2.addAnimation(animation2, forKey: "opacity")

You can only animate following properties with UIView.Animate:
UIView.Frame
UIView.Bounds
UIView.Center
UIView.Transform
UIView.Alpha
UIView.BackgroundColor
UIView.ContentStretch
For more sophisticated animations you have to use CABasicAnimation like in #bjornorri answer.

You guys are correct in that I was trying to animate layers using the incorrect methods. What I ended up doing was replacing the layers with UIImageView and using UIView.Animate to change the Alpha properties.
Not only was this easier to code, it seems that UIImageViews are actually more performant when it comes to images.

Related

How To Adjust Speed of MoveByOffset In Selenium Using C#?

My code is:
By slider_humidity = By.XPath("ExampleXpath");
var hSlider = driver.FindElement(slider_humidity);
Actions action = new Actions(driver);
action.MoveToElement(hSlider, 0, 0); //this will make it to start at 0,0 of the slider
action.ClickAndHold(); //don't pass the element, now it will click current mouse location which is (0,0)
action.MoveByOffset(pixelstomove, 0); // move by 30 pixel from 0
action.Build().Perform();
It seem to be too fast for my targeted website and I need to change the speed of it. It basically goes from point 0 to the given point instantly. I however would like it to slide the slider slowly.
Also alternatives way using Javascript inside C# would be apprecited, as long as I can adjust the speed to my wishes.
Try this:
By slider_humidity = By.XPath("ExampleXpath");
var hSlider = driver.FindElement(slider_humidity);
PointerInputDevice mouse = new PointerInputDevice();
Actions action = new Actions(driver);
action.MoveToElement(hSlider, 0, 0) //this will make it to start at 0,0 of the slider
.ClickAndHold() //don't pass the element, now it will click current mouse location which is (0,0)
.tick(mouse.CreatePointerMove(hSlider, pixelstomove, 0, TimeSpan.FromMilliseconds(200))) // Move by <pixelstomove> in x-offset
.Build()
.Perform();

Applying gradient effect on scroll text in Unity2D

I made this gradient effect. I used SoftMask to mark the place I want to cover with the background getting the gradient effect on text. I know it would be easier to just use image background and make a gradient in photoshop (example). But what if I want things to be more dynamic? For example, I have a video in the background that on click pauses and shows up the same scroll text. Now, the tool that I made wouldn't work because the background in this scenario would be different. I've been searching for a shader that could do the trick, but couldn't find any. Is Unity even capable of doing something like this? The effect is pretty obvious and looks easy to make, but man in was pain in the a** to make this work efficiently.
The gradient effect function:
private void FadeOutTextGradiantAndArrow(Vector2 scrollRectValue)
{
var contentY = _textScrollViewContent.anchoredPosition.y;
var contentMaxY = _textScrollViewContent.rect.height - _textScrollView.GetComponent<RectTransform>().rect.height;
var gradientHeight = _softMaskCanvasGroup.GetComponent<RectTransform>().rect.height;
var contentYSkewed = contentY - (contentMaxY - gradientHeight);
var positionPercentage = contentYSkewed / gradientHeight;
if (contentMaxY - gradientHeight < contentY)
{
_softMaskCanvasGroup.alpha = 1 - positionPercentage;
_arrowBelowTextCanvasGroup.alpha = _softMaskCanvasGroup.alpha;
}
else
{
_softMaskCanvasGroup.alpha = 1;
_arrowBelowTextCanvasGroup.alpha = _softMaskCanvasGroup.alpha;
}
}

Can you get the final value from an animation before that animation has completed?

Say I start a four-second DoubleAnimation on the Canvas.Left property of a control that animates the value from its current value to 100 and that animation was started by calling BeginAnimation on that control in code-behind.
void Animate(Control someControlOnCanvas, int newX){
var canvasLeftAnimation = new DoubleAnimation();
canvasLeftAnimation.To = newX;
canvasLeftAnimation.FillBehavior = FillBehavior.Stop;
canvasLeftAnimation.Duration = new Duration(TimeSpan.FromSeconds(4));
canvasLeftAnimation.Completed += (s, e) => {
Canvas.SetLeft(targetButton, x);
};
someControlOnCanvas.BeginAnimation(Canvas.LeftProperty, canvasLeftAnimation);
}
Animate(somethingToMove, 100);
Say half-way through that animation--at the two-second mark--I need to cancel the current animation and start a new one with a new To position (the From position would be wherever it is right now) that's 100 past where the first animation would end (i.e. not where it currently is at 50, but where it's supposed to be, which is 100, so adding another 100 would yield a new target of 200.)
If I try getting the current Left value, it's the animated value of 50. If I try getting the base value, it's where the animation started, which is zero since it's not officially updated until the completion handler fires.
So outside of manually adding a variable to track where things should be, how can I start a new animation that says 'Go to the original end, plus 100?'
My thoughts are:
Get the existing/current animation
Get it's To value
Start a new animation with the previous animation's To value, plus 100
What I'm stuck on is getting #1.
...or am I going about this all wrong?

Storyboard animation is not in sync with the previous animation

I am trying to implement MiddleClickScrolling in ScrollViewer and it works well.
The problem is when moving the pointer the Storyboard will restart to update the speed but when we move the pointer a jitter is occurring. I have attached a gif but you may not notice this jitter in this gif.
Since this a big class, I can't put all the code here. You can see my full code on GitHub (Note: Please select SmoothScroll branch if you are cloning it). An easy way to reproduce this issue is to move the pointer Up and Down for a small distance rapidly.
This is my code for storyboard animation
_verticalDoubleAnimation = new DoubleAnimation()
{
EnableDependentAnimation = true,
Duration = new TimeSpan(0, 0, 1)
};
//Different function
var offsetX = _currentPosition.X - _startPosition.X;
var offsetY = _currentPosition.Y - _startPosition.Y;
SetCursorType(offsetX, offsetY);
if (CanScrollVertical())
{
if (Math.Abs(offsetY) > _threshold)
{
RunInUIThread(() =>
{
_verticalDoubleAnimation.From = _scrollViewer.VerticalOffset;
_verticalDoubleAnimation.To = _scrollViewer.VerticalOffset + (offsetY > 0 ? _scrollViewer.ScrollableHeight : -_scrollViewer.ScrollableHeight);
if ((_scrollViewer.ScrollableHeight / (Math.Abs(offsetY) * _factor)) == double.NaN)
{
return;
}
_verticalDoubleAnimation.Duration = TimeSpan.FromSeconds(_scrollViewer.ScrollableHeight / (Math.Abs(offsetY) * _factor));
_verticalStoryboard.Begin();
});
}
else
{
RunInUIThread(() =>
{
_verticalStoryboard.Stop();
_sliderVertical.Value = _scrollViewer.VerticalOffset;
});
}
}
Instead of animating it, use a timer or a while loop to dynamically update the position using the ScrollViewer.ChangeView() method. Make sure the interval is less than 16.6ms for smooth 60fps motion. Also make sure to set the final parameter of ChangeView to false so that its built-in animation is disabled.
So in your first commit, change this:
timer = new Timer(ScrollAsync, null, 50, 50);
To this:
timer = new Timer(ScrollAsync, null, 0, 5);
The Timer does not give precision within 1ms or even 10ms to my undestanding. Overcompensating by updating it every 1-5ms should make up for that so it's probably fine and it's what I'm using in my custom scrolling control. A Stopwatch is very precise but is a massive CPU hog. Another option: It's a lot of extra work, but if you want precision timing and maximum performance with minimal battery usage, you can use Win2D's CanvasAnimatedControl which can be used to run code exactly once every 60th of a second.

How to create a smooth animated text marquee?

I know that there are lot of different threads about horizontal text animation/text scrolling, but unfortunately none of them give smooth scrolling with repeatable text. I have tried double/thickness animation using various WPF controls containing text. Also tried animating with visual brush which gives me by far the most elegant scrolling compared to other approaches (for e.g. playing with Canvas.Left property etc.) but that too goes blur the text, if the text length or the animation speed is too high.
I'm over to a pure DirectX C# implementation using SharpDX library. Should also mention that I'm a beginner with DirectX programming. Here is the code:
public void RunMethod()
{
// Make window active and hide mouse cursor.
window.PointerCursor = null;
window.Activate();
var str = "This is an example of a moving TextLayout object with no snapped pixel boundaries.";
// Infinite loop to prevent the application from exiting.
while (true)
{
// Dispatch all pending events in the queue.
window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent);
// Quit if the users presses Escape key.
if (window.GetAsyncKeyState(VirtualKey.Escape) == CoreVirtualKeyStates.Down)
{
return;
}
// Set the Direct2D drawing target.
d2dContext.Target = d2dTarget;
// Clear the target.
d2dContext.BeginDraw();
d2dContext.Clear(Color.CornflowerBlue);
//float layoutXOffset = 0;
float layoutXOffset = layoutX;
// Create the DirectWrite factory objet.
SharpDX.DirectWrite.Factory fontFactory = new SharpDX.DirectWrite.Factory();
// Create a TextFormat object that will use the Segoe UI font with a size of 24 DIPs.
textFormat = new TextFormat(fontFactory, "Verdana", 100.0f);
textLayout2 = new TextLayout(fontFactory, str, textFormat, 2000.0f, 100.0f);
// Draw moving text without pixel snapping, thus giving a smoother movement.
// d2dContext.FillRectangle(new RectangleF(layoutXOffset, 1000, 1000, 100), backgroundBrush);
d2dContext.DrawTextLayout(new Vector2(layoutXOffset, 0), textLayout2, textBrush, DrawTextOptions.NoSnap);
d2dContext.EndDraw();
//var character = str.Substring(0, 1);
//str = str.Remove(0, 1);
//str += character;
layoutX -= 3.0f;
if (layoutX <= -1000)
{
layoutX = 0;
}
// Present the current buffer to the screen.
swapChain.Present(1, PresentFlags.None);
}
}
Basically it creates an endless loop and subtracts the horizontal offset. Here are the challenges: I need repeatable text similar to HTML marquee without any gaps, Would probably need to extend it to multiple monitors.
Please suggest.
I don't know neither how to use DirectX nor sharpdx, but if you want you can consider this solution
I had a similar problem a while ago, but with the text inside a combobox. After a bounty i got what i was looking for. I'm posting the relevant piece of code as an example, but you can check the complete answer here
Basically, whenever you have a textblock/textbox that contain a string that cannot be displayed completely, cause the length exceed the textblock/box lenght you can use this kind of approach. You can define a custom usercontrol derived from the base you need (e.g. SlidingComboBox : Combobox) and define an animation for you storyboard like the following
_animation = new DoubleAnimation()
{
From = 0,
RepeatBehavior = SlideForever ? RepeatBehavior.Forever : new RepeatBehavior(1), //repeat only if slide-forever is true
AutoReverse = SlideForever
};
In my example i wanted this behaviour to be active only when the mouse was on the combobox, so in my custom OnMouse enter i had this piece of code
if (_parent.ActualWidth < textBlock.ActualWidth)
{
_animation.Duration = TimeSpan.FromMilliseconds(((int)textBlock.Text?.Length * 100));
_animation.To = _parent.ActualWidth - textBlock.ActualWidth;
_storyBoard.Begin(textBlock);
}
Where _parent represent the container of the selected item. After a check on the text lenght vs combobox lenght i start the animation and end it at the end of the text to be displayed
Note that in the question i mentioned there are also other soltions. I'm posting the one that worked for me

Categories