Xamarin Android控件特定单元填充

时间:2017-05-01 12:01:40

标签: android android-layout xamarin xamarin.android

我正在尝试在运行时在TextView上创建填充,以便它在所有设备上看起来都一样。

我有2个TextView,它们在RelativeLayout内水平放置。第一个TextView位于布局的左侧,我希望其他TextView有一个左边距或填充,比方说200。

但是什么是200?当我在XAML文件中设置此值时,我可以指定单位,但是当我在运行时设置它时,这就是我需要做的,那么我只能指定int值。

我找不到指定单位类型的位置,所以我可以在所有屏幕分辨率上看一下。

任何帮助表示赞赏:)

1 个答案:

答案 0 :(得分:0)

是的,这是一个真正的痛苦。我有一个解决方案,截至目前,不是一个很好的NuGet包。它将在接下来的几周内完成,但是现在你必须自己完成所有的代码。

首先,您需要一个公共(PCL)界面:

public interface ILayoutService
{
    double GetScaledDouble(double original);
    int GetScaledInt32(int original);
}

接下来,在Android特定的代码中,您需要实现此接口:

public sealed class AndroidLayoutService : ILayoutService
{
    private static double s_standardWidthInches = 3.75;
    private static double s_widthScaleFactor = (double)Android.App.Application.Context.Resources.DisplayMetrics.WidthPixels / (double)Android.App.Application.Context.Resources.DisplayMetrics.DensityDpi / s_standardWidthInches;

    public AndroidLayoutService()
    {
    }

    public double GetScaledDouble(double fontSize)
    {
        return fontSize * s_widthScaleFactor;
    }

    public int GetScaledInt32(int original)
    {
        return (int)(GetScaledDouble(original));
    }
}

现在将该实现放入您选择的DI容器中。我的选择是OpenNETCF IoC以及这些示例将使用的内容,但您可以使用您想要的任何机制 - 您必须根据需要进行调整。基本上你必须从Android原生位到你的Xamarin Forms PCL。

所以我这样做:     RootWorkItem.Services.Add();

现在,在您的PCL中,您需要一个可以接受字符串并通过此缩放机制将其转换为厚度的标记扩展。它看起来像这样(注意DI容器的使用 - 你可能需要根据你的选择改变它):

public sealed class ScaledThickness : IMarkupExtension
{
    private static ILayoutService s_layoutService = OpenNETCF.IoC.RootWorkItem.Services.Get<ILayoutService>();

    public string Thickness { get; set; }

    public object ProvideValue(IServiceProvider serviceProvider)
    {
        if (s_layoutService == null)
        {
            var tc = new ThicknessTypeConverter();
            return tc.ConvertFromInvariantString(Thickness);
        }

        var sizeStrings = Thickness.Split(',');
        var sizes = new int[sizeStrings.Length];
        for (int i = 0; i < sizes.Length; i++)
        {
            sizes[i] = s_layoutService.GetScaledInt32(Convert.ToInt32(sizeStrings[i]));
        }

        switch (sizes.Length)
        {
            case 1:
                return new Thickness(sizes[0]);
            case 2:
                return new Thickness(sizes[0], sizes[1]);
            case 4:
                return new Thickness(sizes[0], sizes[1], sizes[2], sizes[3]);
        }

        throw new Exception("Unable to convert to ScaledThickness: " + Thickness);
    }
}

现在,你通过做这样的事情来消耗所有这些。我使用样式代码清晰度:

<Style x:Key="alarmRow" TargetType="Label">
      <Setter Property="Margin" Value="{opennetcf:ScaledThickness Thickness='10,50,10,50'}" />
</Style>

这一堆代码有什么作用?呈现Label(在XAML中定义)时,将通过扩展名运行标记。样式中提供的厚度首先转换为4个数字:10,50,10和50.这些是通过ILayoutService确定的缩放因子运行,然后用于创建厚度对象,然后将其传递给构造函数Label。是的,它似乎令人费解,但它确实有效。它在小型手机和大型平板电脑上看起来是正确的,并且使用iOS ILayoutService,它也可以在那里工作,只需一个代码库。

再次,我道歉它不是一个更容易使用的形式 - 我将在接下来的几个星期内将所有这些推到OpenNETCF Xamarin Forms NuGet包中,所以你所有人都这样做了要做的就是消耗ScaledThickness的最后一点,但与此同时,这就是我的全部。