Xamarin Forms Drag Image between Views - c#

I have an application in Xamarin Forms, and I need that the user can choose one image from below and drag anywhere he wants to in the top view, the idea is: The below view with the images are the home rooms, and the top view is the Houseplant, the user can create his houseplant by dragging and rotating the images, and then finally save the top view as a jpg or png image.
I've searched here and 2 3 pages of google about drag and etc, but I haven't found anything that could help me with that, I tried pan gesture, tap gesture, but no success =[
Sorry if it is duplicated or something, this is my first post, and I really couldn't find anything.
How can I get this working in Xamarin.Forms or at least with custom renderers and etc?
Thank you guys.
Sample image of what I need

For your image in XAML:
<Image Source="plant.png" x:Name="image"/>
You can actually use pan gesture recognizers to drag and drop images in C#:
Define variables:
double x; // totalX for the pan gesture
double y; // totalY for the pan gesture
Initialize pan gesture and add it to the image:
PanGestureRecognizer panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += PanUpdated;
image.GestureRecognizers.Add(panGesture);
The event handler for the gesture:
void PanUpdated(object sender, PanUpdatedEventArgs args)
{
if (args.StatusType.Equals(GestureStatus.Running)) {
x = args.TotalX;
y = args.TotalY;
image.TranslateTo(x, y, 1);
}
else if (args.StatusType.Equals(GestureStatus.Completed)) {
// set the layout bounds of the image to the new position
// method varies depending on what type of layout you are using for the image
// eg. assume the image is in an absolute layout
// where the layout height is the screen height
// and the layout width is the screen width
Task.Run(() => {
Device.BeginInvokeOnMainThread(async () => // run UI task on main thread
{
await Task.Delay(50); // avoid flickering
var screenWidth = Application.Current.MainPage.Width;
var screenHeight = Application.Current.MainPage.Height;
var b = image.Bounds;
var newBounds = new Rectangle(b.X + x, b.Y + y, b.Width, b.Height);
var newAbsoluteBound =
new Rectangle(newBounds.X / (screenWidth - newBounds.Width),
newBounds.Y / (screenHeight - newBounds.Height),
newBounds.Width / screenWidth,
newBounds.Height / screenHeight);
// set new absolute bounds so a new TranslateTo can be applied
AbsoluteLayout.SetLayoutBounds(image, newAbsoluteBound);
await image.TranslateTo(0, 0, 0);
});
});
}
}

Make sure your page or Image is not in a scrollView.
If ScrollView is enabled for both orientations, Pan-Gesture wont work.
.
.

Related

Show secondary window center of main window in UWP

I started using multiple windows in UWP and need to display secondary windows center of screen or at least center of parent window.
I found nothing relevant about how to specify where to show additional windows on the screen, other than Window.Current.Bounds property.
Here is the simplified version of the method that I am using to create additional windows. The method signature is: CreateFrameWindow(Size size, Type pageType, object parameter)
CoreApplicationView newWindow = CoreApplication.CreateNewView();
ApplicationView newView = null;
bool result = await newWindow.Dispatcher.TryRunAsync(CoreDispatcherPriority.Normal, () =>
{
Frame frame = new Frame();
frame.Navigate(pageType, parameter);
Window.Current.Content = frame;
Window.Current.Activate();
newView = ApplicationView.GetForCurrentView();
});
result = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newView.Id);
newView.TryResizeView(size);
The TryResizeView works fine as long as the secondary window has enough space to resize based on its current location on the screen. I want to enable resize up to the maximum available size (size of window when it is maximized) and place it to the center of the screen. If this is not possible, placing to the center of the parent or main window is acceptable.
Show secondary window center of main window in UWP
CoreApplicationView does not provide api to set the view position manually. For your requirement please try to use AppWindow to archive this feature. And AppWindow has RequestMoveRelativeToDisplayRegion method that position the window in the specified display region at the specified offset. For more please refer official code sample scenario 5
Update
If you want to make your new window display in the center, you need know your windows size before, and calculate X Y value for RequestMoveRelativeToDisplayRegion method.
X = (1920-W)/2 //1920 is Horizontal Resolution W is the new window's width
Y = (1080-H)/2 //1080 is Vertical Resolution H is the new window's height
For get current display resolution please refer this case link
var bounds = ApplicationView.GetForCurrentView().VisibleBounds;
var scaleFactor = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
var size = new Size(bounds.Width*scaleFactor, bounds.Height*scaleFactor);
For AppWindow I'm using...
//Set custom window size
Windows.UI.WindowManagement.Preview.WindowManagementPreview.SetPreferredMinSize(appWindow, new Size(500, 500));
appWindow.RequestSize(new Size(500, 500));
DisplayRegion displayRegion = ApplicationView.GetForCurrentView().GetDisplayRegions()[0];
double displayRegionWidth = displayRegion.WorkAreaSize.Width;
double displayRegionHeight = displayRegion.WorkAreaSize.Height;
int horizontalOffset = (int)(displayRegionWidth - 520); //New window is 500 width + 20 to accomodate for padding
int verticalOffset = (int)(displayRegionHeight - 500); //New window is 500 height
appWindow.RequestMoveRelativeToDisplayRegion(displayRegion, new Point(horizontalOffset / 2 , verticalOffset / 2));

UWP XAML BladeView control - scroll newly-created BladeItem into view

I'm using the BladeView control from Microsoft's Windows Community Toolkit. When the application window is < 640px, the BladeMode property changes to Fullscreen.
When a new blade is created in my code behind, I want the BladeView to scroll to the right so that new blade is displayed. It seems like I should be able to use StartBringIntoView() to accomplish this, but it's not doing anything.
Here's what I'm doing:
if (bladeView.BladeMode == BladeMode.Fullscreen)
{
// current window width
Rect windowBounds = Window.Current.Bounds;
int currentWidth = (int)windowBounds.Width;
// scroll to view
BringIntoViewOptions opts = new BringIntoViewOptions();
Rect target = new Rect { Height = windowBounds.Height, Width = windowBounds.Width, X = currentWidth, Y = 0 };
opts.TargetRect = target;
newBlade.StartBringIntoView(opts);
}
This is what my XAML tree looks like:
I just needed to use bladeView.UpdateLayout() before calling StartBringIntoView().
Example:
if (bladeView.BladeMode == BladeMode.Fullscreen)
{
// update the layout so StartBringIntoView() works
bladeView.UpdateLayout();
// scroll BladeView to newly-created BladeItem
newBlade.StartBringIntoView();
}

Android: Get correct coordinates with scaled and translated canvas

I am writing an Android (Xamarin) application which is able to zoom and pan an image. A user can also click on a position on the image. I need those coordinates on the image for later use.
The following code is zooming and panning the image:
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
_maxX = canvas.Width;
_maxY = canvas.Height;
canvas.Translate(_posX, _posY);
if (_scaleDetector.IsInProgress)
canvas.Scale(_scaleFactor, _scaleFactor, _scaleDetector.FocusX, _scaleDetector.FocusY);
else
canvas.Scale(_scaleFactor, _scaleFactor, _lastGestureX, _lastGestureY);
}
So far so good, now I have some MotionEvent in use, which is a LongPressListener. I wrote the following code to translate the coordinates from the MotionEvent to the coordinates on the image:
var actualX = e.GetX() - (_parent._posX / _parent._scaleFactor);
var actualY = e.GetY() - (_parent._posY / _parent._scaleFactor);
e in this case is the frame of the image. The frame holds an image (which is _parent), the user can drag the image. _parent._posX/Y are changed when that happens. The user can also zoom the image, that's the _scaleFactor.
So, when a user taps anywhere in e, I need to translate those coordinates to the image coordinates.
Those two lines of code works, but when the user zooms in, the coordinates are off as you can see in the attached image:
The red dots represent the calculated positions. As you can see, if a user zooms in the coordinates gets more off. What's wrong in this calculation?
Try to do this :-
var actualX = (e.GetX() - _parent._posX) / _parent._scaleFactor;
var actualY = (e.GetY() - _parent._posY) / _parent._scaleFactor;
I think your problem is because the Canvas is not getting updated, try using Canvas.UpdateLayout after zooming.
I managed to fix it using a Matrix:
private float[] TranslateCoordinates(float[] coordinates)
{
var matrix = new Matrix(Matrix);
matrix.PreScale(_scaleFactor, _scaleFactor);
matrix.PreTranslate(_posX, _posY);
matrix.Invert(matrix);
matrix.MapPoints(coordinates);
return coordinates;
}
The float[] contains the values of MotionEvent's GetX() and GetY().

C# WPF Image Point to Point animation

I need to pan an image at a preset Scale level (no zoom). When panning from left to right, I need the left-side of the image to disappear as the leading right edge appears. This would give the image the appearance of a video as the camera pans the scene. What I've done so far:
double origX = 0.0;
double origY = 0.5;
double newx;
double newy;
image1.RenderTransformOrgin = new Point(origX, origY);
image1.RenderTransform = new ScaleTransform(2.0, 2.0);
if (newX == 0.0)
{
image1.RenderTransformOrgin = new Point(origX, origY);
}
else
{
image1.RenderTransformOrgin = new Point(newX, newY);
}
Using this code I am able to start the virtual "camera lens" on the left and then move it to any other point of the image. By manually increasing newX's value incrementally I am able to create the effect I need. My question is how best to increase the newX value to produce a smooth, animated appearance? Thank You.

Adapting to screen rotation windows phone

I am creating a camera app using MediaCapture. I am trying to adapt to screen rotation and thus I have created the following method:
private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
width = Window.Current.Bounds.Width;
height = Window.Current.Bounds.Height;
//captureManager.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
//if (ApplicationView.GetForCurrentView().Orientation.ToString() == "Portrait") capturePreview.Stretch = Stretch.Fill;
capturePreview.Width = width;
capturePreview.Height = height;
imagePreview.Width = width;
imagePreview.Height = height;
//if (ApplicationView.GetForCurrentView().Orientation.ToString() == "Portrait") capturePreview.Stretch = Stretch.Fill;
//else capturePreview.Stretch = Stretch.Uniform;
}
When I open my app the camera fills the whole page but when I flip the camera the capturePreview only takes half of the page, It doesn't matter if I start the app in portrait or horizontal mode, the other mode won't work but the first mode will also if flipped in to.
Another question is about the actual capturePreview layout, I found that if I keep the screen at horizontal layout the camera works great but if the device is in portrait mode I cant fill the whole page without stretching the photo, is there a way to keep only one element on the screen in a certain rotation (capturePreview) I tried rotating it with a rotation tranform but that also affects the actual place of the element.
Thank you
In WP you get the CurrentViewState through the Window.Sizechanged Event.
See this MSDN article (first result from google)

Categories

Resources