简体   繁体   中英

Remove Button Text If There Isn't Enough Space

I'm working with an item template that should display one or more buttons per item. There are three buttons that I want to be displayed on a horizontal line. Each button has an icon and some text.

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
  </Grid.ColumnDefinitions>
  <Button x:Name="LeftButton"
          Text="Left Button"
          ImageSource="left.png"
          HorizontalOptions="Start"/>
  <Button x:Name="CenterButton"
          Text="Center Button"
          ImageSource="center.png"
          HorizontalOptions="Center"/>
  <Button x:Name="RightButton"
          Text="Right Button"
          ImageSource="right.png"
          HorizontalOptions="End"/>
</Grid>

This is working good so far. The three buttons display the icon and text and they are aligned left, center and right respectively.

Now, I want the buttons to only display the icons, if the container is not wide enough to display all the text. As far as I understand MVVM, this should be the responsibility of the View.

My intended solution would be something like this:

public partial class ItemTemplate : ContentView
// ContentView is our implementation of a UI element.
{
  public ItempTemplate()
  {
    InitializeComponent();
    SizeChanged += HandleSizeChanged;
  }

  private void HandleSizeChanged(object sender, EventArgs e)
  {
    if (/* not enough space */)
    {
      LeftButton.Text = string.Empty;
      CenterButton.Text = string.Empty;
      RightButton.Text = string.Empty;
    }
    else
    {
      LeftButton.Text = "Left Button";
      CenterButton.Text = "Center Button";
      RightButton.Text = "Right Button";
    }
  }
}

Is there any way to know if the container is wide enough for all three button? If possible, I'd like to use a dynamic solution, because the button text will eventually be translated.

You can place the code into a custom contentview, and decide to hide/show the text in the event LayoutChanged according to the container's width.

Custom View xaml
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Button x:Name="LeftButton" Grid.Column="0" Text="Left Button"  ImageSource="dots.png"  HorizontalOptions="Start"/>
        <Button x:Name="CenterButton" Grid.Column="1" Text="Center Button"  ImageSource="dots.png" HorizontalOptions="Center"/>
        <Button x:Name="RightButton" Grid.Column="2" Text="Right Button" ImageSource="dots.png" HorizontalOptions="End"/>
    </Grid>
Custom View code behind
  public partial class MyView : ContentView
    {
        public MyView()
        {
            InitializeComponent();

            this.LayoutChanged += MyView_LayoutChanged;
        }

        private void MyView_LayoutChanged(object sender, EventArgs e)
        {
            var view = sender as View;

            if (view.Width < 200)
            {
                LeftButton.Text = string.Empty;
                CenterButton.Text = string.Empty;
                RightButton.Text = string.Empty;
            }
            else
            {
                LeftButton.Text = "Left Button";
                CenterButton.Text = "Center Button";
                RightButton.Text = "Right Button";
            }
        }
    }

  • Scenario: container is large enough.
xmlns:local="clr-namespace:FormsApp"

<local:MyView/>

在此处输入图像描述

  • Scenario: container is small,wrapped inside another layout.
<Grid HorizontalOptions="Start"  WidthRequest="199" >
        <local:MyView/>
 </Grid>

在此处输入图像描述

I solved my problem by using a custom button implementation (mostly because I needed some other additional features).

The custom button contains an Image and a Label. In addition to the standard button features I need, I added these methods to the code-behind:

public void ExpandText() {
  Label.IsVisible = true;
}

public void CollapseText() {
  Label.IsVisible = false;
}

public bool IsTextCollapsed() {
  return !Label.IsVisible;
}

public double GetWidthAsExpanded() {
  return Image.Width + Label.Width;
}

In the container's code-behind I check if the button's width fits within its container and collapse/expand accordingly. For that to work, I added containers for each button.

public ItemTemplate() {
  InitializeComponent();
  LayoutChanged += HandleLayoutChanged;
}

private static void HandleLayoutChanged(object sender, EventArgs e)
{
  if (!(sender is ItemTemplate itemTemplate))
  {
    return;
  }
  if (itemTemplate.ButtonContainerLeft.Width > itemTemplate.ButtonLeft.GetWidthAsExpanded()
    && itemTemplate.ButtonContainerCenter.Width > itemTemplate.ButtonCenter.GetWidthAsExpanded()
    && itemTemplate.ButtonContainerRight.Width > itemTemplate.ButtonRight.GetWidthAsExpanded())
  {
    ExpandAllButtons(itemTemplate);
  }
  else
  {
    CollapseAllButtons(itemTemplate);
  }
}

Because I added ExpandText and CollapseText earlier, I don't have to "remember" what the text inside the button was, because I just collapse the label within the button. GetWidthAsExpanded will always return the necessary width of the button, even if it is collapsed.

side-note 1: I could've just added the width-check within the custom button implementation, but not every ItemTemplate has all buttons and if any label is collapsed, all labels should be collapsed.

side-note 2: I needed button containers either way, because the left button will either be "Mark as Read" or "Mark as Unread" depending on the state of the ItemTemplate data context. So there are actually two buttons in the first container.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM