I'm having problems zooming into images that are in rows of an UITableView in Xamarin.iOS - ios

I have a tableView inside a tabView, and my rows in the tableView contain images. I would like to zoom into the said images (I put them inside a scrollView and set the max/min zoom and I set ViewForZoomingInScrollView), but it seems I can't get the zoom to trigger because they are small images 50x56 or some other gesture/event is interfeiring. I use the same zoom code on another part of my app and it works perfectly. Has anyone come across the same or similar problem or knows a possible solution?
EDIT:
protected DocumentBaseCell()
: base(UITableViewCellStyle.Default, new NSString("TableCell"))
{
...
documentImage = new UIImageView();
documentImage.Image = UIImage.FromBundle("LaunchImage");
documentImage.ContentMode = UIViewContentMode.ScaleAspectFit;
documentImage.Layer.ZPosition = 0;
imageScrollView = new UIScrollView();
imageScrollView.ClipsToBounds = false;
imageScrollView.ContentSize = new CGSize(50, 56);
imageScrollView.MaximumZoomScale = 8f;
imageScrollView.MinimumZoomScale = 1f;
imageScrollView.Add(documentImage);
imageScrollView.ViewForZoomingInScrollView += (UIScrollView sv) =>
{
imageScrollView.ContentSize = new CGSize(documentImage.Frame.Width, documentImage.Frame.Height);
return documentImage;
};
imageScrollView.DidZoom += (object sender, EventArgs e) =>
{
//(sender as UIView).Layer.ZPosition = 2000;
};
imageScrollView.ZoomingEnded += (object sender, ZoomingEndedEventArgs e) =>
{
(sender as UIScrollView).SetZoomScale(0f, true);
(sender as UIView).Layer.ZPosition = 0;
this.Layer.ZPosition = 0;
};
ContentView.Add(imageScrollView);
...
}
And this is the UpdateCell method:
internal virtual void UpdateCell(DocumentModel doc, string sup, string
docType, string user, string date, UIImage image)
{
if (image != null)
{
this.documentImage.Image = image;
}
...
}
The Frame is set aswell:
public override void LayoutSubviews()
{
base.LayoutSubviews();
imageScrollView.Frame = new CGRect(0, 2, 50, 56);
documentImage.Frame = new CGRect(0, 0, 50, 56);
}

I think you should give a frame to imageScrollView and documentImage, I download the official tableView sample project and add your code there, it zooms well.
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
imageScrollView.Frame = new CGRect(ContentView.Bounds.Width - 233, 5, 133, 133);
headingLabel.Frame = new CGRect(5, 4, ContentView.Bounds.Width - 63, 25);
subheadingLabel.Frame = new CGRect(100, 18, 100, 20);
imageView.Frame = imageScrollView.Bounds;
}
I uploaded a sample project here and you can check it.

Related

Print WebView with multiple pages in Xamarin UWP

I am trying to print web page in xamarin forms. I am using DependencyService to print webview, which I have implemented in android successfully.
For Windows UWP,
I referred to this link:
https://forums.xamarin.com/discussion/91163/problem-with-printing-webview-in-uwp-phone
The approach used in this is printing only the first page of the webpage.
Edit :
I created an interface IPrint providing only the html source to the function.
public interface IPrint
{
void PrintAsync(string htmlSource);
}
In PrintAsync function (in Windows UWP project),
async void IPrint.PrintAsync(string htmlSource)
{
ViewToPrint.NavigateToString(htmlSource);
ViewToPrint.LoadCompleted += ViewToPrint_LoadCompleteAsync;
}
When WebView is completely loaded,
private async void ViewToPrint_LoadCompleteAsync(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
if (PrintDoc != null)
{
printDoc.AddPages -= PrintDoc_AddPages;
printDoc.GetPreviewPage -= PrintDoc_GetPreviewPage;
printDoc.Paginate -= PrintDoc_Paginate;
}
this.printDoc = new PrintDocument();
try
{
printDoc.AddPages += PrintDoc_AddPages;
printDoc.GetPreviewPage += PrintDoc_GetPreviewPage;
printDoc.Paginate += PrintDoc_Paginate;
bool showprint = await PrintManager.ShowPrintUIAsync();
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
PrintDoc = null;
GC.Collect();
}
To add pages in PrintDocument,
private void PrintDoc_AddPages(object sender, AddPagesEventArgs e)
{
printDoc.AddPage(ViewToPrint);
printDoc.AddPagesComplete();
}
To implement multiple pages printing,
I referred this link : https://stackoverflow.com/a/17222629/6366591
I changed AddPages function to the following, but it doesn't seem to work for me.
private void PrintDoc_AddPages(object sender, AddPagesEventArgs e)
{
rectangleList = GetWebPages(ViewToPrint, new Windows.Foundation.Size(100d, 150d));
foreach (Windows.UI.Xaml.Shapes.Rectangle rectangle in rectangleList)
{
printDoc.AddPage(rectangle);
}
printDoc.AddPagesComplete();
}
You can find GetWebPages() function here.
List<Windows.UI.Xaml.Shapes.Rectangle> GetWebPages(Windows.UI.Xaml.Controls.WebView webView, Windows.Foundation.Size page)
{
// ask the content its width
var _WidthString = webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollWidth.toString()" }).GetResults();
int _ContentWidth;
if (!int.TryParse(_WidthString, out _ContentWidth))
throw new Exception(string.Format("failure/width:{0}", _WidthString));
webView.Width = _ContentWidth;
// ask the content its height
var _HeightString = webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollHeight.toString()" }).GetResults();
int _ContentHeight;
if (!int.TryParse(_HeightString, out _ContentHeight))
throw new Exception(string.Format("failure/height:{0}", _HeightString));
webView.Height = _ContentHeight;
// how many pages will there be?
var _Scale = page.Width / _ContentWidth;
var _ScaledHeight = (_ContentHeight * _Scale);
var _PageCount = (double)_ScaledHeight / page.Height;
_PageCount = _PageCount + ((_PageCount > (int)_PageCount) ? 1 : 0);
// create the pages
var _Pages = new List<Windows.UI.Xaml.Shapes.Rectangle>();
for (int i = 0; i < (int)_PageCount; i++)
{
var _TranslateY = -page.Height * i;
var _Page = new Windows.UI.Xaml.Shapes.Rectangle
{
Height = page.Height,
Width = page.Width,
Margin = new Windows.UI.Xaml.Thickness(5),
Tag = new Windows.UI.Xaml.Media.TranslateTransform { Y = _TranslateY },
};
_Page.Loaded += (s, e) =>
{
var _Rectangle = s as Windows.UI.Xaml.Shapes.Rectangle;
var _Brush = GetWebViewBrush(webView);
_Brush.Stretch = Windows.UI.Xaml.Media.Stretch.UniformToFill;
_Brush.AlignmentY = Windows.UI.Xaml.Media.AlignmentY.Top;
_Brush.Transform = _Rectangle.Tag as Windows.UI.Xaml.Media.TranslateTransform;
_Rectangle.Fill = _Brush;
};
_Pages.Add(_Page);
}
return _Pages;
}
WebViewBrush GetWebViewBrush(Windows.UI.Xaml.Controls.WebView webView)
{
// resize width to content
var _OriginalWidth = webView.Width;
var _WidthString = webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollWidth.toString()" }).GetResults();
int _ContentWidth;
if (!int.TryParse(_WidthString, out _ContentWidth))
throw new Exception(string.Format("failure/width:{0}", _WidthString));
webView.Width = _ContentWidth;
// resize height to content
var _OriginalHeight = webView.Height;
var _HeightString = webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollHeight.toString()" }).GetResults();
int _ContentHeight;
if (!int.TryParse(_HeightString, out _ContentHeight))
throw new Exception(string.Format("failure/height:{0}", _HeightString));
webView.Height = _ContentHeight;
// create brush
var _OriginalVisibilty = webView.Visibility;
webView.Visibility = Windows.UI.Xaml.Visibility.Visible;
var _Brush = new WebViewBrush
{
SourceName = webView.Name,
Stretch = Windows.UI.Xaml.Media.Stretch.Uniform
};
_Brush.Redraw();
// reset, return
webView.Width = _OriginalWidth;
webView.Height = _OriginalHeight;
webView.Visibility = _OriginalVisibilty;
return _Brush;
}
#Jerry Nixon's method worked well on my side. Since his code sample was posted on that thread about five years ago. For current UWP APIs, I just done a little changes(e.g, webView.InvokeScriptAsync). I also saw that you call the webView.InvokeScriptAsync method in your code. That's good. But you call the GetResults() method, I did not suggest you call GetResults() method. Because invoking javascript code sometimes will take you a lot of time. You might get the exception A method was called at an unexpected time.
Then, I also noticed that your printing flow is a bit of a mess. Please read Print from your app to learn the standardized printing process.
You could check the official code sample Printing sample for details.
The following was the updated code of your code snippet:
async Task<List<Windows.UI.Xaml.Shapes.Rectangle>> GetWebPages(Windows.UI.Xaml.Controls.WebView webView, Windows.Foundation.Size page)
{
// ask the content its width
var _WidthString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollWidth.toString()" });
int _ContentWidth;
if (!int.TryParse(_WidthString, out _ContentWidth))
throw new Exception(string.Format("failure/width:{0}", _WidthString));
webView.Width = _ContentWidth;
// ask the content its height
var _HeightString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollHeight.toString()" });
int _ContentHeight;
if (!int.TryParse(_HeightString, out _ContentHeight))
throw new Exception(string.Format("failure/height:{0}", _HeightString));
webView.Height = _ContentHeight;
// how many pages will there be?
var _Scale = page.Width / _ContentWidth;
var _ScaledHeight = (_ContentHeight * _Scale);
var _PageCount = (double)_ScaledHeight / page.Height;
_PageCount = _PageCount + ((_PageCount > (int)_PageCount) ? 1 : 0);
// create the pages
var _Pages = new List<Windows.UI.Xaml.Shapes.Rectangle>();
for (int i = 0; i < (int)_PageCount; i++)
{
var _TranslateY = -page.Height * i;
var _Page = new Windows.UI.Xaml.Shapes.Rectangle
{
Height = page.Height,
Width = page.Width,
Margin = new Windows.UI.Xaml.Thickness(5),
Tag = new Windows.UI.Xaml.Media.TranslateTransform { Y = _TranslateY },
};
_Page.Loaded +=async (s, e) =>
{
var _Rectangle = s as Windows.UI.Xaml.Shapes.Rectangle;
var _Brush = await GetWebViewBrush(webView);
_Brush.Stretch = Windows.UI.Xaml.Media.Stretch.UniformToFill;
_Brush.AlignmentY = Windows.UI.Xaml.Media.AlignmentY.Top;
_Brush.Transform = _Rectangle.Tag as Windows.UI.Xaml.Media.TranslateTransform;
_Rectangle.Fill = _Brush;
};
_Pages.Add(_Page);
}
return _Pages;
}
async Task<WebViewBrush> GetWebViewBrush(Windows.UI.Xaml.Controls.WebView webView)
{
// resize width to content
var _OriginalWidth = webView.Width;
var _WidthString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollWidth.toString()" });
int _ContentWidth;
if (!int.TryParse(_WidthString, out _ContentWidth))
throw new Exception(string.Format("failure/width:{0}", _WidthString));
webView.Width = _ContentWidth;
// resize height to content
var _OriginalHeight = webView.Height;
var _HeightString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollHeight.toString()" });
int _ContentHeight;
if (!int.TryParse(_HeightString, out _ContentHeight))
throw new Exception(string.Format("failure/height:{0}", _HeightString));
webView.Height = _ContentHeight;
// create brush
var _OriginalVisibilty = webView.Visibility;
webView.Visibility = Windows.UI.Xaml.Visibility.Visible;
var _Brush = new WebViewBrush
{
SourceName = webView.Name,
Stretch = Windows.UI.Xaml.Media.Stretch.Uniform
};
_Brush.Redraw();
// reset, return
webView.Width = _OriginalWidth;
webView.Height = _OriginalHeight;
webView.Visibility = _OriginalVisibilty;
return _Brush;
}
I used the Printing sample and put my above updated code in it and do some relevant changes, then I could print all web pages successfully.

How to add the Left margin in UITableViewCell iOS Xamarin

How to add the left margin in UITableVIewCell Xamarin iOS.
I have tried the following ways but they does not work
public void initCell( CustomCommentInfo comment )
{
CoreGraphics.CGRect frame = this.ContentView.Frame;
if (comment.level > 0)
{
frame.X = frame.X + (comment.level * 10);
}
this.Frame = frame;
}
and
public void initCell( CustomCommentInfo comment )
{
CoreGraphics.CGRect frame = this.Frame;
if (comment.level > 0)
{
frame.X = frame.X + (comment.level * 10);
}
this.Frame = frame;
}
both of these does not work.
Ok i tried it with an other way that works
I added the view in the cell and added left margin constraints then keep the reference to the left margin in code and change it in code works
In designer.cs
UIKit.NSLayoutConstraint marginCommentCell { get; set; }
and in code behind file
if (comment.level > 0)
{
marginCommentCell.Constant += marginCommentCell.Constant * comment.level;
}
else {
marginCommentCell.Constant = 10; // constant value
}

UITableView with SearchView makes new cells overlap old ones on search

Iam implementing a SearchView to filter the data in my UITableView. Iam able to search successfully, the only issue is when the UITableView data gets filtered, the old cells still exist and the filtered ones overlap them giving me a messy output. I have cleared the Table source as suggested by my answers on SO, but still not resolved the problem.
Here is what Iam trying to do:
FilterController
void searchFiler_TextChanged(object sender, UISearchBarTextChangedEventArgs e)
{
if (!string.IsNullOrEmpty(e.SearchText))
{
ppTable.Source = null;
AppDelegate.filteredList = null;
ppTable.ReloadData();
filteredModelList = filter(dupes, e.SearchText);
mAdapter = new PeoplePlacesSource(filteredModelList, "");
ppTable.Source = mAdapter;
ppTable.ReloadData();
}
else
{
ppTable.Source = null;
mAdapter = new PeoplePlacesSource(dupes, "");
searchFiler.TextChanged += searchFiler_TextChanged;
mAdapter.TableRowSelected += mAdapter_TableRowSelected;
ppTable.Source = mAdapter;
ppTable.ReloadData();
}
}
PeoplePlacesSource
public override UITableViewCell GetCell(UITableView tableView, Foundation.NSIndexPath indexPath)
{
cell = tableView.DequeueReusableCell("PeoplePlacesCell_Cell") as PeoplePlacesCell ?? PeoplePlacesCell.Create();
subList = userList.ElementAt(indexPath.Row);
cell.UpdatePeoplePlacesCell(subList);
return cell;
}
PeoplePlacesCell
internal void UpdatePeoplePlacesCell(System.Linq.IGrouping<string, Models.EmployeeModel> subList)
{
var yPosition =15;
var xPosition = 10;
var imgDefault = new UIImageView();
imgDefault.Frame = new CoreGraphics.CGRect(10, viewParent.Frame.Y, 60,60);
imgDefault.Image = UIImage.FromFile("ic_appicon.png");
CALayer profileImageCircle = imgDefault.Layer;
profileImageCircle.CornerRadius = 28;
profileImageCircle.BorderWidth = 2;
profileImageCircle.BorderColor = new CoreGraphics.CGColor(211, 34, 41);
profileImageCircle.MasksToBounds = true;
imgDefault.ClipsToBounds = true;
viewParent.AddSubview(imgDefault);
var labelUserName = new UILabel();
labelUserName.Frame = new CoreGraphics.CGRect(0, 0, viewContainer.Frame.Width, 30);
labelUserName.TextColor = UIColor.FromRGB(211, 34, 41);
labelUserName.Text = subList.Key ;
labelUserName.ClipsToBounds = true;
labelUserName.Font = UIFont.BoldSystemFontOfSize(17);
viewContainer.AddSubview(labelUserName);
var mList = subList.Take(5);
foreach (var employeeModel in mList)
{
var labelPlace = new UILabel();
labelPlace.Frame = new CoreGraphics.CGRect(0, yPosition, viewContainer.Frame.Width, 50);
if (employeeModel.Place.Contains(","))
{
labelPlace.Text = employeeModel.Place.Substring(0, employeeModel.Place.IndexOf(","));
}
else
{
labelPlace.Text = employeeModel.Place;
}
labelPlace.Font = UIFont.FromName(labelPlace.Font.Name, 12f);
labelUserName.SizeToFit();
labelPlace.ClipsToBounds = true;
viewContainer.AddSubview(labelPlace);
yPosition += 15;
}
}
How can I solve this? Any help is appreciated
Do you have the same problem after scroll? You cells are reused, but I don't see code for removing added subviews. Try to remove all subviews you added, before reusing cells.

add sub view if it doesn't exist

on item click I add sub view (UIButton) to my supper view and want to remove it old one when user click again or just change title it isn't first click.
this is my custom renderer:
var text = new UIButton ();
protected override void OnElementChanged (ElementChangedEventArgs<Image> e)
{
base.OnElementChanged (e);
if (Control == null)
return;
if (this.Element != null) {
Original = (SpecLogoImage)this.Element;
}
TargetView = Control as UIImageView;
text.Layer.CornerRadius = 5;
text.Font = UIFont.FromName ("DIN Condensed", text.Font.PointSize);
text.TouchUpInside += delegate {
text.RemoveFromSuperview ();
};
var rec = new UILongPressGestureRecognizer (() => {
text.SetTitle(Original._hint, UIControlState.Normal);
text.TitleLabel.LineBreakMode = UILineBreakMode.WordWrap;
text.SizeToFit ();
text.Frame = new CGRect ((UIApplication.SharedApplication.KeyWindow.Frame.Width / 2.0f) - (250 / 2.0f),
this.Superview.Superview.Superview.Frame.Height / 2.0f, 250, text.Frame.Height);
if (text.Superview==null) {
Animate (0.6f, () => {
this.Superview.Superview.Superview.AddSubview (text);
}, () => {
text.Layer.ZPosition = int.MaxValue;
});
}
});
text.SetTitleColor (UIColor.White, UIControlState.Normal);
text.BackgroundColor = UIColor.Black;
TargetView.UserInteractionEnabled = true;
TargetView.AddGestureRecognizer (rec);
}
}
every time user click Superview is null, what is the problem ?

Animate a layout constraint constant from one value to another using Xamarin.ios

I am using Xamarin studio and developing an iPad app with Xamarin.iOS.
I am setting a constant value against a layout constraint outlet in my c# file.
What I have at the moment (no animations)
_myRightSpaceConstraint.Constant = 50;
What I want
Animate this constant so that it goes from:
_myRightSpaceConstraint.Constant = 300;
to
_myRightSpaceConstraint.Constant = 50;
OR, similar to above but don't specifiy what the start constant is (300), instead I just take whatever it is set to in the xib file and animate to 50.
Is this possible to do this in Xamarin and if so are there any code examples to help me?
What I have tried - which doesnt work
UIView.BeginAnimations ("slideAnimation");
float _pt;
_pt = _myRightSpaceConstraint.Constant;
UIView.SetAnimationDuration (5);
UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
UIView.SetAnimationDelegate (this);
UIView.SetAnimationDidStopSelector (
new Selector ("slideAnimationFinished:"));
_myRightSpaceConstraint.Constant = 50;
UIView.CommitAnimations ();
This actually sets the constant successfully to 50 but with no animation.
Edit/Update:
I managed to achieve what I wanted with the following:
_myRightSpaceConstraint.Constant = 150;
_myViewWithTheConstraint.SetNeedsUpdateConstraints ();
UIView.BeginAnimations ("slideAnimation");
UIView.SetAnimationDuration (1);
UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
UIView.SetAnimationDelegate (this);
UIView.SetAnimationDidStopSelector (
new Selector ("slideAnimationFinished:"));
_myViewWithTheConstraint.LayoutIfNeeded ();
UIView.CommitAnimations ();
The following line was the key:
_myViewWithTheConstraint.LayoutIfNeeded ();
Call LayoutIfNeeded() on the constrained views, as part of the animations action of UIView.Animate:
NSLayoutConstraint[] dynConstraints;
UIView redView;
UIView greenView;
public ContentView()
{
BackgroundColor = UIColor.Blue;
redView = new UIView() {
BackgroundColor = UIColor.Red,
TranslatesAutoresizingMaskIntoConstraints = false
};
AddSubview(redView);
greenView = new UIView(){
BackgroundColor = UIColor.Green,
TranslatesAutoresizingMaskIntoConstraints = false
};
AddSubview(greenView);
var viewsDictionary = new NSMutableDictionary();
viewsDictionary["red"] = redView;
viewsDictionary["green"] = greenView;
dynConstraints= NSLayoutConstraint.FromVisualFormat("V:|-[red]-100-[green(==red)]-|", 0, new NSDictionary(), viewsDictionary);
AddConstraints(dynConstraints);
AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|-[red]-|", 0, new NSDictionary(), viewsDictionary));
AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|-[green(==red)]", 0, new NSDictionary(), viewsDictionary));
this.UserInteractionEnabled = true;
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
foreach(var constraint in dynConstraints)
{
constraint.Constant = 50;
}
UIView.Animate(0.5, () => {
redView.LayoutIfNeeded();
greenView.LayoutIfNeeded();
});
}
I managed to achieve what I wanted with the following:
_myRightSpaceConstraint.Constant = 150;
_myViewWithTheConstraint.SetNeedsUpdateConstraints ();
UIView.BeginAnimations ("slideAnimation");
UIView.SetAnimationDuration (1);
UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
UIView.SetAnimationDelegate (this);
UIView.SetAnimationDidStopSelector (
new Selector ("slideAnimationFinished:"));
_myViewWithTheConstraint.LayoutIfNeeded ();
UIView.CommitAnimations ();
The following line was the key:
_myViewWithTheConstraint.LayoutIfNeeded ();

Resources