(我最初在Xamarin论坛上发布了这个,但后来我决定在这里得到更快的答案?)TL; DR:有些布局会计算透明背景上的点击,其他布局则不会.在容器上设置InputTransparent为其所有子项设置它,我觉得孩子应该能够覆盖父项.我需要创建覆盖另一个元素的元素,并通过透明区域传递水龙头,但仍然有可点击的按钮.当我尝试使用网格时,它不起作用.我不想回到AbsoluteLayouts.我现在主要在iOS工作,我不太确定它是不是Android的问题.Windows Phone/UWP不在桌面上.
更长的版本:
我正在重写一些在较旧的Xamarin Forms(我认为1.3)中运行正常的布局.我们最近升级到2.1,它对布局代码的错误决定造成了严重破坏.我的任务是更新布局以表现自己.虽然我认识2.2已经发布,但我只是尝试升级,我输入的所有内容在该版本中也是如此,所以它不是2.1和2.2的问题,或者至少如果做了一些改进他们没有帮助我.
它是一个地图应用程序,因此所有布局的核心都是昂贵的,不稳定的OpenGL元素.这个元素非常不喜欢被重新定义,所以我采用了类似于这个虚构的XAML的布局:
<ContentPage>
<CustomLayout>
<OurHeaderControl />
<TheMapControl />
<OurFooterControl />
<MapOverlay />
</CustomLayout>
</ContentPage
Run Code Online (Sandbox Code Playgroud)
"MapOverlay"的目的是通过在页眉/页脚区域和/或地图上添加Xamarin元素来实现我们的工作流程.例如,一个布局会在页脚上方的底部添加一个方向列表,因此它显示的地图空间较小.自定义布局理解这一点并在叠加后布局地图,以便它可以请求正确的地图边界.
在这种布局中,我无法点击MapOverlay结束的任何内容.我可以把它变成InputTransparent并点击那些东西,但是它的所有子节点也都是不可点击的.在旧版面中不是这样.
这是我在旧布局和新布局之间看到的唯一区别:
旧的布局是AbsoluteLayouts的一个复杂的混乱.它看起来像这样,我没写它:
<ContentPage>
<AbsoluteLayout> // "main layout"
<AbsoluteLayout> // "map layout"
<Map /> // An AbsoluteLayout containing the OpenGL view.
</AbsoluteLayout>
<AbsoluteLayout> // "child layout"
<SubPage /> // An AbsoluteLayout
</AbsoluteLayout>
</AbsoluteLayout>
</ContentPage>
Run Code Online (Sandbox Code Playgroud)
主布局包含AbsoluteLayouts以约束子视图.一个子视图本身就是一个AbsoluteLayout,它包含Map和一些与之关联的其他元素.另一个子项是叠加层,它始终是一个AbsoluteLayout,其中包含与该叠加层相关的元素.这些布局都以周期相互引用,并在布局事件发生变化时相互更新.这是一个迷人的乒乓球,最终落户.通常.有时候事情就会消失.显然我有一个改写它的原因.
但我可以点击我需要在每一层点击的内容,但我没有得到.
所以,让我们谈谈我需要做些什么,也许可以弄清楚它是否是一个错误,为什么它不起作用,或者它是否与其他布局一起使用是巧合.这是一个非XAML页面布局,演示了我的项目源于你不能在共享库中使用XAML的日子:
我需要能够点击此UI中的两个按钮并让它们做出响应.
public class MyPage : ContentPage {
public MyPage() {
var mainLayout = new AbsoluteLayout();
// Two buttons will be overlaid.
var overlaidButton = new Button() {
Text = "Overlaid",
Command = new Command((o) => DisplayAlert("Upper!", "Overlaid button.", "Ah."))
};
mainLayout.Children.Add(overlaidButton, new Rectangle(0.25, 0.25, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize), AbsoluteLayoutFlags.PositionProportional);
// The top overlay layout will be a grid.
var overlay = new Grid() {
RowDefinitions = { new RowDefinition() { Height = new GridLength(1.0, GridUnitType.Star) } },
ColumnDefinitions = {
new ColumnDefinition() { Width = new GridLength(1.0, GridUnitType.Star) },
new ColumnDefinition() { Width = new GridLength(1.0, GridUnitType.Star) },
},
BackgroundColor = Color.Transparent
};
var overlayingButton = new Button() {
Text = "Overlaying",
Command = new Command((o) => DisplayAlert("Upper!", "Overlaying button.", "Ah."))
};
overlay.Children.Add(overlayingButton, 0, 1);
mainLayout.Children.Add(overlay, new Rectangle(0, 0, 1.0, 1.0), AbsoluteLayoutFlags.All);
// This pair of property sets makes the overlaid button clickable, but not the overlaying!
// overlay.InputTransparent = true;
// upperOverlayButton.InputTransparent = false;
Content = mainLayout;
}
}
Run Code Online (Sandbox Code Playgroud)
这只允许我点击"覆盖"按钮,即使我将网格更改为AbsoluteLayout.
我很难过.我花了两周的时间来调试初始布局并提出了一个新的解决方案.我真的不想拆解所有的布局,并将所有内容放在一个大的AbsoluteLayout或自定义布局中.在WPF中,有两种透明:"透明背景"意味着背景仍然可以进行测试,"空背景"意味着背景不会受到测试.有没有办法在Xamarin中叠加这样的布局?
或者,更合适的是,为什么我们旧布局中的众多AbsoluteLayouts的复杂嵌套像我需要的那样工作,但这个更简单的布局不是?
更新
这是我记得的一些额外信息:
总的来说,与其他两个平台相比,iOS 的行为似乎是如何InputTransparent
处理的Grid
。我不确定此时是否会将当前行为量化为错误,但我知道遇到平台行为差异令人沮丧。
不过,如果我理解正确的话,可以针对您的情况进行各种修复。似乎之前提交过类似的报告,并且通过此 SO 链接提到了有关 iOS 的行为。这个问题是在非 Forms iOS 应用程序的范围内提出的,但逻辑可以在这里应用。
通过使用自定义渲染器(让我们以 aCustomGrid
为例),您可以具体实现 的 iOS 实现,Grid
以遵循上述链接查找底层视图的方式:
CustomGrid.cs (PCL):
public class CustomGrid : Grid
{
public CustomGrid() { }
}
Run Code Online (Sandbox Code Playgroud)
CustomGrid.cs (iOS):
[assembly: ExportRenderer(typeof(CustomGrid), typeof(CustomGridRenderer))]
public class CustomGridRenderer : ViewRenderer
{
public override UIKit.UIView HitTest(CoreGraphics.CGPoint point, UIKit.UIEvent uievent)
{
UIView hitView = base.HitTest(point, uievent);
if (hitView == this)
{
return null;
}
return hitView;
}
}
Run Code Online (Sandbox Code Playgroud)
以这种方式,您不应该InputTransparent
为 iOS显式设置,并且网格本身上的任何点击都会发送到下面的任何内容。InputTransparent
但是,由于 Android 使用,因此在这种特殊情况下,您可以将其包装在Device.OnPlatform
语句中,如果您不想,则跳过实现 Android 自定义呈现器:
Device.OnPlatform(Android: () =>
{
overlay.InputTransparent = true
});
Run Code Online (Sandbox Code Playgroud)
使用上面的代码修改为使用CustomGrid
和 iOS 渲染器,我可以点击两个按钮。
归档时间: |
|
查看次数: |
5848 次 |
最近记录: |