2016-12-02 89 views
0

我想实现一种包含2个图像的“用户控件”。当我按下它时,图像源被倒置。当我释放时,图像与原始来源一起恢复。 但是,Xamarin轻拍手势不管理“按下”状态。因此,我决定将按下并释放的手势附加到各自的本地组件(Droid,iOS)。我认为自定义渲染器可以救我,但它根本不起作用:在我的Droid渲染器中,“Control”为空,所以我无法附加Touch事件。有任何想法吗 ?Xamarin Forms:具有自定义渲染器的高级ContentView组件

这里我的 “用户控制” 组件的代码:

XAML

<?xml version="1.0" encoding="UTF-8"?> 
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xam_Test.Views.DoubleImageView"> 
    <ContentView.Content> 
     <Grid> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="Auto"/> 
       <ColumnDefinition Width="Auto"/> 
      </Grid.ColumnDefinitions> 

      <Image Source="{Binding FirstImageSource}" Aspect="AspectFit" HeightRequest="{Binding ImageSize}"/> 

      <Image Grid.Column="1" Margin="10,0,0,0" Source="{Binding SecondImageSource}" Aspect="AspectFit" HeightRequest="{Binding ImageSize}"/> 
     </Grid> 
    </ContentView.Content> 
</ContentView> 

代码隐藏

public partial class DoubleImageView : ContentView 
    { 
     public static readonly BindableProperty FirstImageSourceProperty = BindableProperty.Create("FirstImageSource", typeof(string), typeof(DoubleImageView), string.Empty); 
     public string FirstImageSource 
     { 
      set { SetValue(FirstImageSourceProperty, value); } 
      get { return (string)GetValue(FirstImageSourceProperty); } 
     } 


     public static readonly BindableProperty ImageSizeProperty = BindableProperty.Create("ImageSize", typeof(int), typeof(DoubleImageView), 44); 
     public int ImageSize 
     { 
      set { SetValue(ImageSizeProperty, value); } 
      get { return (int)GetValue(ImageSizeProperty); } 
     } 


     public static readonly BindableProperty SecondImageSourceProperty = BindableProperty.Create("SecondImageSource", typeof(string), typeof(DoubleImageView), string.Empty); 
     public string SecondImageSource 
     { 
      set { SetValue(SecondImageSourceProperty, value); } 
      get { return (string)GetValue(SecondImageSourceProperty); } 
     } 


     public ICommand SwitchImageCommand { get; set; } 

     public DoubleImageView() 
     { 
      BindingContext = this; 
      SwitchImageCommand = new Command<bool>((bool isPressed) => UpdateImages(isPressed)); 
      InitializeComponent(); 
     } 

     private void UpdateImages(bool isPressed) 
     { 
      string source; 
      if (isPressed) 
      { 
       source = SecondImageSource; 
       SecondImageSource = FirstImageSource; 
       FirstImageSource = source; 
      } 
      else 
      { 
       source = FirstImageSource; 
       FirstImageSource = SecondImageSource; 
       SecondImageSource = source; 
      } 
     } 
    } 

在这里,我的Droid渲染

[assembly: ExportRenderer(typeof(DoubleImageView), typeof(DoubleImageViewRenderer))] 
namespace YourNameSpace.Droid.Renderers 
{ 
    class DoubleImageViewRenderer : ViewRenderer 
    { 
     private ICommand _updateUICommand; 

     protected override void Dispose(bool disposing) 
     { 
      //MANAGE touch events 
      if (_updateUICommand != null) 
      { 
       Control.Touch -= Image_Touch; 
      } 

      _updateUICommand = null; 

      base.Dispose(disposing); 
     } 

     protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e) 
     { 
      base.OnElementChanged(e); 

      if (Control == null) 
      { 
       var view = (Context as Activity).LayoutInflater.Inflate(Resource.Layout.doubleimage, this, false); 
       var firstImage = view.FindViewById<ImageView>(Resource.Id.first_imageView); 
       var secondImage = view.FindViewById<ImageView>(Resource.Id.second_imageview); 
       // ?????? 
       SetNativeControl(view); 
      } 

      if (Control != null) 
      { 
       DoubleImageView formView = (e.NewElement as DoubleImageView); 

       ExtractFormData(formView); 

       //MANAGE touch events 
       if (_updateUICommand != null) 
       { 
        Control.Touch += Image_Touch; 
       } 
      } 
     } 

     private void Image_Touch(object sender, TouchEventArgs e) 
     { 
      var handled = false; 
      if (e.Event.Action == MotionEventActions.Down) 
      { 
       _updateUICommand.Execute(true); 
       handled = true; 
      } 
      else if (e.Event.Action == MotionEventActions.Up) 
      { 
       _updateUICommand.Execute(false); 

       handled = true; 
      } 

      e.Handled = handled; 
     } 

     /// <summary> 
     /// Extract form view data 
     /// </summary> 
     /// <param name="formImage">form view object</param> 
     private void ExtractFormData(DoubleImageView formView) 
     { 
      _updateUICommand = formView.SwitchImageCommand; 
     } 
    } 
} 

编辑

显然,我要创建一个Android布局管理渲染SetNativeControl我的自定义组件。这里我的自定义布局。

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 
    <ImageView android:id="@+id/first_imageview"/> 
    <ImageView android:id="@+id/second_imageview"/> 
</LinearLayout> 

我不知道如何绑定我的android布局与我的表单属性。

回答

0

如果你派生自ViewRenderer,你的控件将为null。您必须使用SetNativeControl(view)进行设置。

在iOS设备上使用

UIView view = new UIView(); 
view.Add(...) 
SetNativeControl(view) 

对于Android的,如果您有布局:

var view = (this.Context as Activity).LayoutInflater.Inflate(Resource.Layout.MyLayout, this, false); 
SetNativeControl(view); 
+0

你能给我一些细节吗?任何教程了解这部分? 我是Xamarin的初学者,我不是和android开发者。 我试图创建一个布局,其中包含两个ImageView像我的窗体,用android:id来访问它们,这要感谢FindViewById(我认为这是必要的)。 但是,如何映射imageview组件与我的DoubleImageView属性? – Klaonis

+0

请分享你完整的解决方案,我会看看 –

+0

我没有比我第一篇文章的内容更多的东西。 我可以添加我的布局内容,但它很荒谬。 我试图整合你的代码,但我不知道如何去做绑定android和表单数据的魔法。 – Klaonis

0

看起来你需要告诉你的ViewRenderer什么它实际上是渲染。有默认的渲染,如EntryRenderer和ImageRenderer。我有一个自定义的轻拍手势渲染器,我使用的是...

ViewRenderer<GestureControl, Android.Widget.RelativeLayout> 
相关问题