我使用此代码设置NavBar的背景,这在Retina和非Retina显示器中非常有效。有一个@ 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;
}
以下是应用Hue后非Retina和Retina显示的结果:
答案 0 :(得分:3)
忽略这些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
对象,该对象具有正确的“比例”信息,以便在UINavigationBar
中正确显示。
答案 1 :(得分:2)
我从未尝试使用CoreImage,但是对于CoreGraphics,您需要使用UIGraphics.BeginImageContextWithOptions
并指定0
进行缩放(因此它将自动完成Retina和非Retina显示)。
所以我要尝试的第一件事是替换你的:
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 ();
更新:FromContext
在iOS中无法使用(特定于OSX),因此上述代码无效。
答案 2 :(得分:0)
提交了MonoTouch团队的错误。将很快发布解决方案。
答案 3 :(得分:0)
我现在有三个'黑客'建议:
通过替换此行来强制修剪图像的范围:
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);
但是你在调整后的图像上失去了'Retina分辨率(它使用@ 2x图像作为光源,但是在应用滤镜后仅显示它的左下象限,这要归功于图像原点从底部开始-left)。
沿着相同的行,您可以缩放从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);
不幸的是你再次失去了Retina分辨率,但至少图像显示正确(只是下采样到320宽)。
您可以将过滤后的图像保存到磁盘,然后使用“磁盘”上的图像文件设置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);
}
最终黑客的好处是图像看起来正确(即视网膜分辨率得以保留)。
我仍然在寻找“完美”的解决方案,但至少这些想法会“单独解决”你的问题...