Xamarin表单 - IOS问题 - 内容视图嵌套在彼此之上

时间:2016-10-27 14:46:29

标签: ios xamarin.ios xamarin.forms

我在Xamarin表单中创建了一个翻转视图的控件(如卡片样式)。这两个视图都有某种输入(EX:按钮列表),如果你进行交互,将会翻转" Card"控制到下一个视图。我能够使用Android,但是当我使用IOS进行测试时,控件似乎被禁用,我无法点击任何事件。现在我通过使用e.NativeView.UserInteractionEnabled属性解决了类似的问题。唯一的问题是这个属性只能在初始化视图时使用,我希望能够使用更具动态性的类似东西。

IOS问题略有进展。

<?xml version="1.0" encoding="utf-8" ?>
<TemplatedView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="minto.qm.mobile.Views.Controls.PanelView">
  <TemplatedView.ControlTemplate>
    <ControlTemplate>
      <AbsoluteLayout>
//the last item in this list will be the dominant control on runtime
//the other views input will not work 
        <ContentView Content="{TemplateBinding BackContent}" AbsoluteLayout.LayoutBounds="1,1,1,1" AbsoluteLayout.LayoutFlags="WidthProportional,HeightProportional,PositionProportional" AnchorX="0.5" AnchorY="0.5"></ContentView>
        <ContentView Content="{TemplateBinding FrontContent}" AbsoluteLayout.LayoutBounds="1,1,1,1" AbsoluteLayout.LayoutFlags="WidthProportional,HeightProportional,PositionProportional" AnchorX="0.5" AnchorY="0.5"></ContentView>
      </AbsoluteLayout>
    </ControlTemplate>
  </TemplatedView.ControlTemplate>
</TemplatedView>

有没有人知道这样的任何功能?

https://forums.xamarin.com/discussion/81114/how-to-create-a-custom-controls-with-multiple-view-on-top-of-each-other

更新

这是控件的后面代码:

public partial class PanelView : TemplatedView
    {
        public event EventHandler FrontContentAppeared;
        public event EventHandler BackContentAppeared;

        public static readonly BindableProperty FrontContentProperty = BindableProperty.Create(nameof(FrontContent), typeof(View), typeof(PanelView), defaultValue: null, propertyChanged: OnFrontContentChanged);
        public static readonly BindableProperty BackContentProperty = BindableProperty.Create(nameof(BackContent), typeof(View), typeof(PanelView), defaultValue: null, propertyChanged: OnBackContentChanged);
        public static readonly BindableProperty SwitchViewProperty = BindableProperty.Create(nameof(SwitchView), typeof(bool), typeof(PanelView), defaultValue: false, propertyChanged: OnSwitchViewChanged);

        private bool _isFrontView = true;

        public PanelView()
        {
            InitializeComponent();
        }

        private async void SwitchCurrentView()
        {
            if (_isFrontView)
            {
                BackContent.IsVisible = true;
                //BackContent.InputTransparent = true;
                FrontContent.Unfocus();
                BackContent.Focus();

                await Task.WhenAll(
                    FrontContent.FadeTo(0, 500, Easing.Linear),
                    BackContent.FadeTo(1, 500, Easing.Linear),
                    this.RotateYTo(GetRotation(0, 180), 250, Easing.Linear)
                );
                FrontContent.IsVisible = false;
                //FrontContent.InputTransparent = false;
                BackContentAppeared?.Invoke(this, EventArgs.Empty);
            }
            else
            {
                FrontContent.IsVisible = true;
                //FrontContent.InputTransparent = true;
                FrontContent.Focus();
                BackContent.Unfocus();

                await Task.WhenAll(
                    FrontContent.FadeTo(1, 500, Easing.Linear),
                    BackContent.FadeTo(0, 500, Easing.Linear),
                    this.RotateYTo(GetRotation(180, 180), 250, Easing.Linear)
                );
                BackContent.IsVisible = false;
                //BackContent.InputTransparent = false;
                FrontContentAppeared?.Invoke(this, EventArgs.Empty);
            }

            _isFrontView = !_isFrontView;
            SwitchView = false;
        }

        private static void OnFrontContentChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var self = (PanelView)bindable;
            self.SetFrontContentView((View)newValue);
        }

        private static void OnBackContentChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var self = (PanelView)bindable;
            self.SetBackContentView((View)newValue);
        }

        private static void OnSwitchViewChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var self = (PanelView)bindable;
            self.SwitchView = (bool)newValue;
            if (self.SwitchView)
            {
                self.SwitchCurrentView();
            }
        }

        private void SetFrontContentView(View view)
        {
            FrontContent = view;
            if (!_isFrontView)
            {
                FrontContent.IsVisible = false;
                view.FadeTo(0, 1, Easing.Linear);
            }
        }

        private void SetBackContentView(View view)
        {
            view.FadeTo(0, 1, Easing.Linear);
            view.RotateYTo(180, 1, Easing.Linear);
            BackContent = view;
            if (_isFrontView)
            {
                BackContent.IsVisible = false;
            }
        }

        private double GetRotation(double start, double amount)
        {
            var rotation = (start + amount) % 360;
            return rotation;
        }

        protected override void OnBindingContextChanged()
        {
            base.OnBindingContextChanged();

            if (FrontContent != null)
            {
                SetInheritedBindingContext(FrontContent, BindingContext);
            }
            if (BackContent != null)
            {
                SetInheritedBindingContext(BackContent, BindingContext);
            }
        }

        public View FrontContent
        {
            get { return (View)GetValue(FrontContentProperty); }
            set { SetValue(FrontContentProperty, value); }
        }

        public View BackContent
        {
            get { return (View)GetValue(BackContentProperty); }
            set { SetValue(BackContentProperty, value); }
        }

        public bool SwitchView
        {
            get { return (bool)GetValue(SwitchViewProperty); }
            set { SetValue(SwitchViewProperty, value); }
        }
    }

当可绑定的bool变量SwitchView更改时,动画运行

private void OnRoomTypeTapped(object sender, GliderItemTappedEventArgs e)
        {
            if (e.IsSelected && e.IsSelected == e.LastSelection)
            {
                PanelView.SwitchView = true;
            }
        }

更新

Xaml Page示例。注意:(基本:ExtendedPage是一个自定义内容页面)和(控件:滑翔机是自定义视图,上面有按钮列表)

<?xml version="1.0" encoding="utf-8" ?>
<base:ExtendedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:minto.qm.mobile.Views.Controls;assembly=minto.qm.mobile"
             xmlns:base="clr-namespace:minto.qm.mobile.Views.Pages.Base;assembly=minto.qm.mobile"
             x:Class="minto.qm.mobile.Views.Pages.RoomPage"
             Navigation="{Binding Navigation, Mode=OneWayToSource}"
             Title="Room">
  <base:ExtendedPage.Content>
    <ScrollView>
      <StackLayout Spacing="0">
        <ContentView BackgroundColor="#3498DB" Padding="10">
          <Label Text="{Binding SelectedRoomName}" FontAttributes="Bold" HorizontalTextAlignment="Center" VerticalTextAlignment="Center"></Label>
        </ContentView>
        <StackLayout Spacing="5" Padding="10, 20, 10, 10">
          <controls:PanelView x:Name="PanelView">
            <controls:PanelView.FrontContent>
              <controls:Glider ItemsSource="{Binding RoomTypes}" DisplayProperty="Name" SelectedIndex="0" ItemSelected="OnRoomTypeSelected" ItemTapped="OnRoomTypeTapped" Orientation="Vertical" Lines="3" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"></controls:Glider>
            </controls:PanelView.FrontContent>
            <controls:PanelView.BackContent>
              <controls:Glider ItemsSource="{Binding Rooms}" DisplayProperty="Name" SelectedIndex="0" ItemSelected="OnRoomSelected" ItemTapped="OnRoomTapped" Orientation="Horizontal" Lines="5" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"></controls:Glider>
            </controls:PanelView.BackContent>
          </controls:PanelView>
          <StackLayout Orientation="Horizontal">
            <Label Text="Room annotation:" FontAttributes="Bold" Margin="5, 0, 0, 0" VerticalTextAlignment="Center"></Label>
            <Button Text="&#60;" FontAttributes="Bold" HorizontalOptions="EndAndExpand" VerticalOptions="Center" BackgroundColor="Transparent" WidthRequest="50" HeightRequest="50" Clicked="OnExpandButtonClicked" FontSize="Medium" AnchorX="0.5" AnchorY="0.5"></Button>
          </StackLayout>
          <Entry x:Name="AnnotationEditor" HorizontalOptions="FillAndExpand" BackgroundColor="#4D4D4D" TextChanged="Entry_OnTextChanged"/>
          <Button Text="Next" Command="{Binding NextPageCommand}" HorizontalOptions="FillAndExpand" />
        </StackLayout>
      </StackLayout>
    </ScrollView>
  </base:ExtendedPage.Content>
  <base:ExtendedPage.Overlay>
    <controls:Tombstone Token="{Binding DeficiencyToken}" BackgroundColor="#444444"></controls:Tombstone>
  </base:ExtendedPage.Overlay>
  <base:ExtendedPage.ToolbarItems>
    <ToolbarItem Text="Details" Order="Primary" Priority="0" Clicked="DetailsClicked"></ToolbarItem>
  </base:ExtendedPage.ToolbarItems>
</base:ExtendedPage>
public partial class RoomPage : ExtendedPage
    {
        public ViewModels.Pages.RoomPage ViewModel => _vm ?? (_vm = BindingContext as ViewModels.Pages.RoomPage);
        private ViewModels.Pages.RoomPage _vm;

        private bool _buttonExpanded;

        public RoomPage()
        {
            InitializeComponent();
            BindingContext = new ViewModels.Pages.RoomPage();
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            ViewModel.OnAppearing();
            HandleCaching();
        }

        private async void HandleCaching()
        {
            await Task.Run(() =>
            {
                var pageCache = Services.Caches.Pages.GetInstance();
                pageCache.Preload(nameof(InspectionGalleryPage), new InspectionGalleryPage());
            });
        }

        private void DetailsClicked(object sender, EventArgs e)
        {
            ShowOverlay = !ShowOverlay;
        }

        private void Entry_OnTextChanged(object sender, TextChangedEventArgs e)
        {
            ViewModel.RoomAnnotations = e.NewTextValue;
        }

        private void OnRoomTypeSelected(object sender, GliderItemSelectedEventArgs e)
        {
            ViewModel.SelectedRoomTypeName = e.Item.ToString();
        }

        private void OnRoomTypeTapped(object sender, GliderItemTappedEventArgs e)
        {
            if (e.IsSelected && e.IsSelected == e.LastSelection)
            {
                PanelView.SwitchView = true;
            }
        }

        private void OnRoomSelected(object sender, GliderItemSelectedEventArgs e)
        {
            ViewModel.SelectedRoomName = e.Item.ToString();
        }

        private void OnRoomTapped(object sender, GliderItemTappedEventArgs e)
        {
            if (e.IsSelected && e.IsSelected == e.LastSelection)
            {
                PanelView.SwitchView = true;
            }
        }

        private void AnimateHeight(View view, double end)
        {
            view.Animate("Expander", value => view.HeightRequest = value, view.Height, end, 2, 250, Easing.Linear);
        }

        private void OnExpandButtonClicked(object sender, EventArgs e)
        {
            var button = (Button) sender;
            if (_buttonExpanded)
            {
                button.RotateTo(0, 250, Easing.Linear);
                AnimateHeight(AnnotationEditor, 45.5);
            }
            else
            {
                button.RotateTo(-90, 250, Easing.Linear);
                AnimateHeight(AnnotationEditor, 300);
            }
            _buttonExpanded = !_buttonExpanded;
        }
    }

1 个答案:

答案 0 :(得分:0)

正如我所说,“某事”正在覆盖你的按钮。这是有问题的声明

  <AbsoluteLayout>
    <ContentView Content="{TemplateBinding BackContent}" BackgroundColor="Transparent" AbsoluteLayout.LayoutBounds="1,1,1,1" AbsoluteLayout.LayoutFlags="WidthProportional,HeightProportional,PositionProportional" AnchorX="0.5" AnchorY="0.5"></ContentView>
    <ContentView Content="{TemplateBinding FrontContent}" BackgroundColor="Transparent" AbsoluteLayout.LayoutBounds="1,1,1,1" AbsoluteLayout.LayoutFlags="WidthProportional,HeightProportional,PositionProportional" AnchorX="0.5" AnchorY="0.5"></ContentView>
  </AbsoluteLayout>

您的FrontContent ContentView涵盖BackContent ContentView。当您旋转和隐藏内容时,您实际使用按钮而不是视图。我发现这个设计比它应该更复杂,但不管这不是问题。以下是解决方案。当您隐藏内容(含义按钮)时,也会隐藏您的父视图并在显示按钮时显示它。

private async void SwitchCurrentView()
{
    if (_isFrontView)
    {
        BackContent.IsVisible = true;
       ((ContentView)BackContent.Parent).IsVisible = true;//************************

        FrontContent.Unfocus();
        BackContent.Focus();

        await Task.WhenAll(
            FrontContent.FadeTo(0, 500, Easing.Linear),
            BackContent.FadeTo(1, 500, Easing.Linear),
            this.RotateYTo(GetRotation(0, 180), 250, Easing.Linear)
        );
        FrontContent.IsVisible = false;
        ((ContentView)FrontContent.Parent).IsVisible = false;//******************

        BackContentAppeared?.Invoke(this, EventArgs.Empty);
    }
    else
    {
        FrontContent.IsVisible = true;
        ((ContentView)FrontContent.Parent).IsVisible = true;

        FrontContent.Focus();
        BackContent.Unfocus();

        await Task.WhenAll(
            FrontContent.FadeTo(1, 500, Easing.Linear),
            BackContent.FadeTo(0, 500, Easing.Linear),
            this.RotateYTo(GetRotation(180, 180), 250, Easing.Linear)
        );
        BackContent.IsVisible = false;
        ((ContentView)BackContent.Parent).IsVisible = false;

        FrontContentAppeared?.Invoke(this, EventArgs.Empty);
    }

    _isFrontView = !_isFrontView;
    SwitchView = false;
}