I am very new to Xamarin. What I am trying to do is build a simple application that has 3 images on it. Each image needs to slide horizontally to show the next image. I got this idea from a children's game called "mix and match". The game lets you change the head, body and feet of a cartoon animals.
So if I have a set of 5 images that are split into thirds (head,body,feet), how can I display the images on the screen so I can get them to slide?
I tried to stack 3 gallery controls but I could not get the images to fill the screen.
The screen should look something like this;
Can this be built in Xamarin for Android or IOS?
Thanks for any help.
For iOS you could use UIPageControl. You would have a different UIPageControl object for Head, Body, Feet. The idea is that you will have an UIView with a UIScrollView (also three of them). UIScrollView will contain all the different parts of body (e.g. heads). PageControl will handle the swipe gesture recognition and animations and you will set which part of the UIScrollView should be shown in UIPageControls event ValueChanged. The code will look something like this:
In ViewDidLoad:
First you add the five head parts to UIScrollView. I assume that you have these five head parts in an array of UIViews called headPageViews.
RectangleF frame;
for (int i=0; i<5; i++)
{
UIView pageView = headPageViews[i];
frame = headPageViews[i].Frame;
// change Frame.X so that the views are next to each other in scrollView
frame.X = i * this.scrollViewHead.Frame.Width;
pageView.Frame = frame;
this.scrollViewHead.AddSubViews(pageView);
}
In ViewDidLoad: Next you set up the UIPageControl which you added through interface builder:
this.pageControlHead = new UIPageControl(frame);
this.pageControlHead.HidesForSinglePage = true;
this.pageControlHead.ValueChanged += HandlePageControlHeadValueChanged;
this.pageControlHead.Pages = 5; this.viewHead.AddSubview(this.pageControlHead);
Somewhere in code: At last you handle the ValueChanged event:
private void HandlePageControlHeadValueChanged(object sender, EventArgs e)
{
this.scrollViewHead.SetContentOffset(new PointF(this.pageControlHead.CurrentPage * this.scrollViewHead.Frame.Width, 0), true);
}
Repeat these steps for other body parts and you should have the desired effect.
You can also use 3 UIScrollViews in a UIViewController positioned as the image you have added, and set that UIScrollView to enable paging.
set the cropped sections of image in those UIScrollViews, then you would be able to achieve it easily.
Hope this helps.
Related
Lets say I have 100 json data and 50 data instantiated when application starts, now I have to instatiate more data when I scroll down and it reaches to bottom as shown in gif image below.
Please help, I have no idea how to do it.
For a dynamic filling of a scrollview with on-demand loading, you would need to know when your scrollview is at the bottom and check if it can load any items.
I have used a similar approach for an inventory system, where the amount of items in your inventory can be practically infinite. And you do not want to load an infinite amount of items obviously.
// 0.025f works for me, it determines the sensitivity of how close to the bottom you would need to be
if (_scrollRect.normalizedPosition.y < 0.025f && _hasItems)
{
// Check for additional items and add them to your scrollview
YourMethod();
// If there are no more items to be loaded, set a class variable
_hasItems = false;
}
You would need to build your own logic around this code and set _hasItems to true upon start or something similar.
I have a user control which consists of two controls and four buttons, arranged on a Form: the two controls are on the sides and the buttons in the middle in a vertical row.
When using the control in an app, I place it on a form.
Now, when re-sizing the form horizontally, the two controls just move left or right w/o changing their size.
What I need is that the controls stay anchored to the middle of the form and grow to the sides (sorry about the lack of clarity, I prepared screenshots but the site wouldn't let me attach them).
Is there a way to accomplish this without overriding the Resize event?
Use a TableLayoutPanel as base for your user control.
You need 3 columns and one row. The middle column needs to have a fixed size, and the other 2 you set to 50%. Not to worry, .Net is smart enough to calculate the percent they actually take.
Inside the right and left columns you put your controls and set the Dock property of both to fill. In the middle column you put a panel and set it's Dock property to fill as wall, and In that panel you put the buttons in the middle.
Set your table layout panel Dock to fill as well, and when adding the user control to the form use Dock top, bottom or fill as well.
Erratum:
The above code works most of the time, but it fails for certain Move-Resize sequences. The solution is to respond to the Move and Resize events of the parent form (the consumer of the control), not of the control itself.
One more thing: due to the event firing order (Move first followed by Resize, had to move the working code from Resize() to Move(), which seems counterintuitive but it seems the right way nevertheless.
It seems indeed that it cannot be done in the Designer, but here is the solution using overrides.
It works ok, except for some control flickering which I haven't been able to overcome.
public partial class SB : UserControl
{
//variables to remember sizes and locations
Size parentSize = new Size(0,0);
Point parentLocation = new Point (0,0);
......
// we care only for horizontal changes by dragging the left border;
// all others take care of themselves by Designer code
public void SB_Resize(object sender, EventArgs e)
{
if (this.Parent == null)
return;//we are still in the load process
// get former values
int fcsw = this.parentSize.Width;//former width
int fclx = this.parentLocation.X;//former location
Control control = (Control)sender;//this is our custom control
// get present values
int csw = control.Parent.Size.Width;//present width
int clx = control.Parent.Location.X;//present location
// both parent width and parent location have changed: it means we
// dragged the left border or one of the left corners
if (csw != fcsw && clx != fclx)
{
int delta = clx - fclx;
int lw = (int)this.tableLayoutPanel1.ColumnStyles[0].Width;
int nlw = lw - delta;
if (nlw > 0)
{
this.tableLayoutPanel1.ColumnStyles[0].Width -= delta;
}
}
this.parentSize = control.Parent.Size;//always update it
this.parentLocation = control.Parent.Location;
}
//contrary to documentation, the Resize event is not raised by moving
//the form, so we have to override the Move event too, to update the
//saved location
private void SB_Move(object sender, EventArgs e)
{
if (this.Parent == null)
return;//we are still in the load process
this.parentSize = this.Parent.Size;//always update it
this.parentLocation = this.Parent.Location;
}
}
The above code works most of the time, but it fails for certain Move-Resize sequences. The solution is to respond to the Move and Resize events of the parent form (the consumer of the control), not of the control itself.
One more thing: due to the event firing order (Move first followed by Resize, had to move the working code from Resize() to Move(), which seems counterintuitive but it seems the right way nevertheless.
How do I do the following I'm not asking for specific code but I need some direction as I have been racking my brains on this for weeks. Simply I want to make a map of the eg. united states and each state is a different picture or area that can be moused over and clicked. I tried playing with png and transparencies but I'm at a dead end. More ambitiously I'd like to drag labels with state capitals over each state and drop them there then have a process where if the label/capital matches the state it correct else it's not.
I've tried GIS(?) I want to do this C# but I can't get traction how to do it so far. Can anyone help? Is this too difficult in C#? SHould i be using another approach? Please what is the approach?
The good news first: The programming part is not so hard and even with good old Winforms you can do the core checks in a few lines. The clickable areas can't be Buttons in Winforms, however.
Here are two solutions:
Solution 1 : You can define a list of areas, called regions and test if one got clicked.
Here is a start: I define a very simple Rectangle Region and a not so simple Polygon Region and test on each click if one was hit. If it was hit I output its data into the Form's title text:
//..
using System.Drawing.Drawing2D;
//..
public Form1()
{
InitializeComponent();
// most real states don't look like rectangles
Region r = new Region(new Rectangle(0, 0, 99, 99));
regions.Add(r);
List<int> coords = new List<int>() {23,137, 76,151, 61,203,
117,283, 115,289, 124,303, 112,329, 76,325, 34,279, 11,162};
List<Point> points = new List<Point>();
for (int i = 0; i < coords.Count ; i += 2)
points.Add(new Point(coords[i], coords[i+1]));
byte[] fillmodes = new byte[points.Count];
for (int i = 0 ; i < fillmodes.Length; i++) fillmodes[i] = 1;
GraphicsPath GP = new GraphicsPath(points.ToArray(), fillmodes);
regions.Add(r);
}
List<Region> regions = new List<Region>();
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
using (Graphics G = pictureBox1.CreateGraphics() )
foreach(Region r in regions)
{
Region ri = r.Clone();
ri.Intersect(new Rectangle(e.X, e.Y, 1, 1));
if (!ri.IsEmpty(G)) // hurray, we got a hit
{ this.Text = r.GetBounds(G).ToString(); break; }
}
}
The regions in the test programm are not visible. For testing you may want to add something like this:
private void button1_Click(object sender, EventArgs e)
{ // paint a non-persistent filling
using (Graphics G = pictureBox1.CreateGraphics())
foreach (Region r in regions)
{ G.FillRegion(Brushes.Red, r); }
}
But now for the bad news: You can define regions to be complicated polygons that look like real states, however that is a lot of work! There are ready-made image map editors out there in the web for making clickable maps on websites. Your best course might be to use one of these to create all those polygons and then convert the html output to a list of points you can read into your program. You may even get lucky and find ready image maps for the USA, but I haven't looked..
Update: There are many image maps of the USA out there. One is even on wikipedia. Converting these coordinates to fit your map will be a task but lot easier than creating them from scratch, imo. I have changed the code to include one list of cordinates from the wikipedia source. Guess the state!
I have implmented a program that lets you click on a state and displays the name in 78 lines of code, excluding the text file with the 50 states.
Solution 2:
Instead of a list of polygons you can prepare a colored map and use the colors as keys into a Dictionary<Color, string> or Dictionary<Color, StateInfo>. You must make sure that each state has one unique color and that the image is not compressed as jpeg, which would introduce artifacts and mess up the key mapping.
Next you map each color to the related info; this is the real work because you must know those states to create the Dictionary ;-)
Finally you can look up the clicked color in the Dictionary you have created:
Color c = ((Bitmap) pictureBox1.Image).GetPixel(e.X, e.Y)
string StateName = stateDictionary[c];
If you are using a class or struct as your value in the dictionary you can include the capital etc..
You can zoom but must scale the click location accordingly; you can even display a geographical Image if you look up the key color not in the PictureBox but in an invisible color code bitmap.
All in all an even simpler solution imo.. your pick!
Once you got that working, you can play with drag&drop. Here you'll want to test on DragDrop or maybe on Mouseup to see where you have dropped the Label.
This is a nice project and well worth of creating a few classes to make things easier and more expandable..!
For real Buttons you may get lucky with WPF.
So I have a custom Button class in a Winforms app written in C# 4.0. The button holds a static image normally, but when a refresh operation takes place it switches to an animated AJAX-style button. In order to animate the image I have a timer set up that advances the image animation on every tick and sets that as the button image. That's the only way I can get it to work. The solution I have isn't that efficient; any advice would be helpful.
So two questions:
1. Is there an easier way - as in am I overlooking some feature I should be using?
2. Is there a better way to manually animate the image?
Find code below of what I'm doing on each tick. The first area of improvement: maybe copy each frame of the image to a list? Note the _image.Dispose(); failing to dispose of a local Image was causing memory leaks.
Thanks for any advice here. I will post something online and link it once I have an efficient solution.
private void TickImage()
{
if (!_stop)
{
_ticks++;
this.SuspendLayout();
Image = null;
if(_image != null)
_image.Dispose();
//Get the animated image from resources and the info
//required to grab a frame
_image = Resources.Progress16;
var dimension = new FrameDimension(_image.FrameDimensionsList[0]);
int frameCount = _image.GetFrameCount(dimension);
//Reset to zero if we're at the end of the image frames
if (_activeFrame >= frameCount)
{
_activeFrame = 0;
}
//Select the frame of the animated image we want to show
_image.SelectActiveFrame(dimension, _activeFrame);
//Assign our frame to the Image property of the button
Image = _image;
this.ResumeLayout();
_activeFrame++;
_ticks--;
}
}
I guess Winforms is not so reach in animation capabilities on its own. If you want more advanced animation use may consider some third-party solutions.
I think you should not load image from resource every tick. The better way is to preload image frames one and hold the reference. Then use it to set appropriate frame every tick.
As I've recently tested, animated gifs are animating well without any additional coding, at least on standard buttons. But if you still need to aminate frames manually, you may try something like this:
// put this somewhere in initialization
private void Init()
{
Image image = Resources.Progress16;
_dimension = new FrameDimension(image.FrameDimensionsList[0]);
_frameCount = image.GetFrameCount(_dimension);
image.SelectActiveFrame(_dimension, _activeFrame);
Image = image;
}
private void TickImage()
{
if (_stop) return;
// get next frame index
if (++_activeFrame >= _frameCount)
{
_activeFrame = 0;
}
// switch image frame
Image.SelectActiveFrame(_dimension, _activeFrame);
// force refresh (NOTE: check if it's really needed)
Invalidate();
}
Another option is to use ImageList property with preloaded static frames and cycle ImageIndex propery just as you do it with SelectActiveFrame above.
I am trying to make a tool in c# which allows the user to put a grid on the screen on a picturebox. At the moment i don't know how to do this, so when a button is clicked, the picturebox comes up with a grid. It needs to be a grid which is spaced out enough that users can find out locations of objects on the picture in the picturebox. Help with what code i can use to do this would be very helpful as i was going to use ControlPaint.DrawGrid but not sure of the values i need to put in it to get my desired effect?
Thanks
Form the Documentation od controlpaint.Drawgrid,
I suppose you need to decide on the cell size in x- amd y-direction and pass this as a size parameter to Drawgrid:
public static void DrawGrid(
Graphics graphics,
Rectangle area,
Size pixelsBetweenDots,
Color backColor
)
for example, a 100*200 pixels square grid would be generated by
setting graphcis to the context you want to draw upon,
Setting area to the top left right and bottom parameters of your image
setting size.x to 100 and size.y to 200
setting color to any color you like.
Update
Something like this should do.
Rectangle myRect = new System.drawings.Rectangle();
myRect.Location := new System.Drawing.Point(0,0);
myRect.Height = 50;
myRect.Width = 50;
Drawgrid(FromImage(yourImage), mygrid , yourImage.Size, System.Drawing.Color.Black);
Disclaimer: i don't develope in c#, so above code is not tested for anything. I just picked stuff from the documentation (msdn).