MonoTouch:双倍外观在Retina显示屏上调整色调时的图像大小
我使用在Retina和非Retina显示器中工作良好的代码来设置NavBar的背景。 有一个@ 2x和正常的图像。 所以,一切都好:
UINavigationBar.Appearance.SetBackgroundImage( GetImage(ImageTheme.menubar), UIBarMetrics.Default);
现在,当我将这个ChangeHue()
变换应用到图像以调整其色调时,在Retina上显示图像的大小是它的两倍。 非Retina显示器是好的:
UINavigationBar.Appearance.SetBackgroundImage( ChangeHue(GetImage(ImageTheme.menubar)), UIBarMetrics.Default); ... UIImage ChangeHue(UIImage originalImage){ var hueAdjust = new CIHueAdjust() { Image = CIImage.FromCGImage(originalImage.CGImage), Angle = hue * (float)Math.PI / 180f // angles to radians }; var output = hueAdjust.OutputImage; var context = CIContext.FromOptions(null); var cgimage = context.CreateCGImage(output, output.Extent); var i = UIImage.FromImage(cgimage); return i; }
这是应用色相后的非视网膜和视网膜显示的结果:
忽略这些HACK,然后在ChangeHue
方法中编辑这一行:
var i = UIImage.FromImage(cgimage);
改为这样做:
float scale = 1f; if (UIScreen.MainScreen.RespondsToSelector (new MonoTouch.ObjCRuntime.Selector ("scale"))) { scale = UIScreen.MainScreen.Scale; // will be 2.0 for Retina } var i = new UIImage(cgimage, scale, UIImageOrientation.Up);
这应该返回一个UIImage
对象, UIImage
对象具有正确的“比例”信息,以正确显示在UINavigationBar
。
我从来没有尝试CoreImage,但对于CoreGraphics,你需要使用UIGraphics.BeginImageContextWithOptions
和指定为0
缩放(所以这将自动完成视网膜和非视网膜显示)。
所以我会尝试的第一件事是取代你的:
var context = CIContext.FromOptions(null);
与以下块:
UIGraphics.BeginImageContextWithOptions (new SizeF (size, size), false, 0); using (var c = UIGraphics.GetCurrentContext ()) { var context = CIContext.FromContext (c); ... } UIGraphics.EndImageContext ();
更新 :从iOS上不能使用FromContext
(这是特定于OSX),所以上面的代码将无法正常工作。
MonoTouch团队提出了一个错误。 很快就会发布解决scheme。
我现在有三个“黑客”build议:
黑客#1
通过replace这一行来强制修剪图像:
var cgimage = context.CreateCGImage(output, output.Extent);
有了这个:
var extent = output.Extent; if (UIScreen.MainScreen.RespondsToSelector (new MonoTouch.ObjCRuntime.Selector("scale"))) { if (UIScreen.MainScreen.Scale == 2f) { extent = new System.Drawing.RectangleF(extent.X, extent.Y, extent.Width / 2f, extent.Height / 2f); } } var cgimage = context.CreateCGImage(output, extent);
但是,如果在调整后的图像上使用了@ 2x图像,则“丢失”Retina分辨率,但是在应用滤镜后仅显示左下象限,这要归功于从左下angular开始的图像原点) 。
黑客#2
沿着同样的路线,您可以缩放从ChangeHue
方法返回的图像,使其不会在导航栏之外展开:
var hued = ChangeHue (navBarImage); if (hued.RespondsToSelector(new MonoTouch.ObjCRuntime.Selector("scale"))) hued = hued.Scale (new System.Drawing.SizeF(320, 47)); UINavigationBar.Appearance.SetBackgroundImage (hued, UIBarMetrics.Default);
不幸的是,你再次失去了视网膜分辨率,但至less图像显示正确(只是缩小到320宽)。
黑客#3
您可以将过滤的图像保存到磁盘,然后使用“磁盘”上的映像文件设置UIAppearance
。 代码看起来像这样:
bool retina = false; if (UIScreen.MainScreen.RespondsToSelector (new MonoTouch.ObjCRuntime.Selector ("scale"))) { if (UIScreen.MainScreen.Scale == 2f) { retina = true; } } if (retina) { NSError err; // unitialized UIImage img = ChangeHue (navBarImage); img.AsPNG ().Save ("tempNavBar@2x.png", true, out err); if (err != null && err.Code != 0) { // error handling } UINavigationBar.Appearance.SetBackgroundImage (UIImage.FromFile ("tempNavBar.png"), UIBarMetrics.Default); } else { UINavigationBar.Appearance.SetBackgroundImage (ChangeHue (navBarImage), UIBarMetrics.Default); }
这个最后的黑客的好处是图像看起来是正确的(即保留视网膜分辨率)。
我仍然在寻找“完美”的解决scheme,但至less这些想法是单向或者另一个“解决”你的问题。