Visual Studio 如何在.net maui中为不同设备在图像上放置按钮并调整内容

p1iqtdky  于 2023-11-21  发布在  .NET
关注(0)|答案(2)|浏览(158)

我想在.net Maui中创建一个用户界面,在特定位置上有一个图像和按钮,如above.

每个圆圈都是一个按钮,在标签“local do toque”中显示身体的区域,如肩膀,肘部等。
我在xaml中使用的部分代码如下

<AbsoluteLayout>
   <Image x:Name="corlett" Source="corlett2.png" Aspect="Fill" HorizontalOptions="Center" Scale="0.9" Margin="-20,20,0,0"></Image>
           
   <Grid>
       <Button x:Name="OmbroDAnt" CornerRadius="25" BackgroundColor="Transparent" BorderColor="Green" 
               BorderWidth="1" Margin="38,100,10,10" Scale="0.6"></Button>
   </Grid>
   <Grid>
       <Button x:Name="OmbroEAnt" CornerRadius="25" BackgroundColor="Transparent" BorderColor="Green" 
               BorderWidth="1" Margin="118,100,10,10" Scale="0.6"></Button>
   </Grid>

   <Grid>
       <Button x:Name="ClaviculaDAnt" CornerRadius="25" BackgroundColor="Transparent" BorderColor="Green" 
               BorderWidth="1" Margin="64,98,10,10" Scale="0.5"></Button>
   </Grid>
   <Grid>
       <Button x:Name="ClaviculaEAnt" CornerRadius="25" BackgroundColor="Transparent" BorderColor="Green" 
               BorderWidth="1" Margin="91,98,10,10" Scale="0.5"></Button>
   </Grid>
   ------

    <Grid>
        <Label x:Name="locationLabel" Text="Local do toque:" Margin="150,500"/>
    </Grid>
</AbsoluteLayout>

字符串
然而,项目的位置根据设备的变化。我已经尝试了FlexLayout,VestricalStackLayout,但没有一个允许我把按钮放在图像上,只有AbsoluteLayout。我如何解决这个问题?非常感谢!

e0bqpujr

e0bqpujr1#

你可以使用AbsoluteLayout来完成这个操作,但是你必须指出元素的位置/大小与其父元素成比例。为此,你需要使用AbsoluteLayoutFlags来指示你提供的值是如何被接受的。
在您的特定情况下,我首先不会在绝对布局中使用边距,如果您需要指定边距以正确定位Image,请在布局中而不是内部进行。然后Image应该覆盖布局的所有空间以具有更容易的比例,否则您需要计算可能应用于图像的任何缩放/平移。
然后,例如,你可以检查肩膀上的左圆是从左边开始的宽度的1/5和从顶部开始的高度的1/6,然后你可以像下面这样设置它的值:

<AbsoluteLayout 
   ...>
   
   ...
        
    <Button 
        x:Name="OmbroDAnt" 
        AbsoluteLayout.LayoutFlags="All"
        AbsoluteLayout.LayoutBounds="0.20, 0.17, 0.02, 0.02"
        CornerRadius="25" 
        BackgroundColor="Transparent" 
        BorderColor="Green"
        BorderWidth="1"  />

   ...

字符串
所以AbsoluteLayout.LayoutFlags="All"将表示您将使用比例位置和大小,AbsoluteLayout.LayoutBounds表示它们每个的值:x,y,width,height。您可以找到更多信息here (AbsoluteLayout class)和这里(Layouts -> AbsoluteLayout)
对于图像,如果没有添加缩放/平移,则您将有:

AbsoluteLayout.LayoutFlags="All"
    AbsoluteLayout.LayoutBounds="0, 0, 1, 1"


也许你需要根据设备屏幕的大小和图像的比例来计算和设置AbsoluteLayout的大小,这样一切都适合它,并且图像在每个设备上都以相同的大小比例显示,从而保持其比例。
希望有帮助!

dpiehjr4

dpiehjr42#

您可以直接在Image上添加TapGestureRecognizer,并使用GetPosition来解析(x, y)相对于图像的坐标:

<Image x:Name="corlett" Source="corlett2.png">
    <Image.GestureRecognizers>
        <TapGestureRecognizer Tapped="OnTapGestureRecognizerTapped" />
    </Image.GestureRecognizers>
</Image>

个字符
请参阅https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/gestures/tap?view=net-maui-7.0
一个有趣的算法存在于一个二次隐藏图像中,每个点击位置都有一个独特的颜色。有了它,我们可以使用这个图像通过解析点击位置的像素颜色来快速识别用户点击的任何点:


的数据
实现此功能的一种方法需要使用第三方SkiaSharp包,并且您将图像放置在SkiaSharp可以加载的位置。对于此示例,我将其放置在Resources/Raw/rawidentify2.png中,然后我可以将rawidentify2.png加载到SKBitmap中,以便稍后在手势识别器期间用于识别:

public partial class MainPage : ContentPage
{
    SkiaSharp.SKBitmap identifyBitmap = null;
    IDictionary<Color, string> color_to_bodypart = new Dictionary<Color, string>()
    {
        {  Color.FromArgb("#ed1c24"), "Left Shoulder" },
        {  Color.FromArgb("#00a2e8"), "Left Clavical" },
        {  Color.FromArgb("#22b14c"), "Right Clavical" },
        {  Color.FromArgb("#ff7f27"), "Right Shoulder" },
        // ...
    };

    public MainPage()
    {
        InitializeComponent();

        Task.Run( async () =>
        {
            Assembly assembly = GetType().GetTypeInfo().Assembly;
            var stream = await FileSystem.OpenAppPackageFileAsync("rawidentify2.png");
            if (stream != null)
            { 
                identifyBitmap = SkiaSharp.SKBitmap.Decode(stream);
            }
        } );
    }

    void OnTapGestureRecognizerTapped(System.Object sender, Microsoft.Maui.Controls.TappedEventArgs e)
    {
        // Position relative to a View
        View view = (View)sender;
        Point? viewPos = e.GetPosition(view);
        // Debug.WriteLine($"viewPos = {viewPos}");

        // Position relative to internal image.
        double s = Math.Max((double)identifyBitmap.Width / view.Width,
                            (double)identifyBitmap.Height / view.Height);
        int imageX = (int)(viewPos.Value.X * s);
        int imageY = (int)(viewPos.Value.Y * s);
        // Debug.WriteLine($"imagePos = {imageX} {imageY}");

        // lookup body part based on relative position
        if (imageX >= 0 && imageX < identifyBitmap.Width && imageY >= 0 && imageY <= identifyBitmap.Height)
        {
            SkiaSharp.SKColor c = identifyBitmap.GetPixel(imageX, imageY);
            Color c2 = new Color(c.Red, c.Green, c.Blue, c.Alpha);
            // Debug.WriteLine($"identify color = {c} {c2}");
            if (color_to_bodypart.ContainsKey(c2))
            {
                var bodypart = color_to_bodypart[c2];
                Debug.WriteLine($"identify bodypart = {bodypart}");
            }
        }
    }
}

相关问题