[OnTouchEvent在Xamarin Android自定义渲染器中从未调用

问题描述 投票:0回答:1

我已经为Android创建了自定义渲染器,并为自定义Slider控件实现了它。我有2个解决方案。在这两种解决方案中,都会在Android Phone上构建并启动Android App。测试程序显示滑块很好,我可以上下拖动拇指而没有任何问题。第二种解决方案是应在其中实施滑块的更大解决方案。如果我运行该解决方案,则会显示滑块,但无法上下移动拇指。永远不会触发OnTouchEvent。以下是Slider所需的所有代码。我知道很多,但我希望有人能看到我的问题。

我的猜测是,找不到或触发了命名空间上的ExportRenderer属性。 'OnElementChanged'替代被调用,但是什么也没有。

这是Android项目中DraggableView(滑块的拇指)的自定义渲染器

using Android.Content;
using Android.Views;
using TGB.Xamarin.Forms.TestApp.Droid.Renderers.Views;
using TGB.Xamarin.Forms.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using static TGB.Xamarin.Forms.Views.DraggableView;
using xam = global::Xamarin.Forms;

[assembly: ExportRenderer(typeof(DraggableView), typeof(DraggableViewRenderer))]
namespace TGB.Xamarin.Forms.TestApp.Droid.Renderers.Views
{
    public class DraggableViewRenderer : VisualElementRenderer<xam.View>
    {
        float originalX;
        float originalY;
        float dX;
        float dY;
        bool firstTime = true;
        bool touchedDown = false;

        public DraggableViewRenderer(Context context) : base(context) { }

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

            if (e.OldElement != null)
            {
                LongClick -= HandleLongClick;
            }

            if (e.NewElement != null)
            {
                LongClick += HandleLongClick;

                var dragView = Element as DraggableView;

                dragView.RestorePositionCommand = new Command(() =>
                {
                    if (!firstTime)
                    {
                        SetX(originalX);
                        SetY(originalY);
                    }
                });
            }
        }

        private void HandleLongClick(object sender, LongClickEventArgs e)
        {
            var dragView = Element as DraggableView;

            if (firstTime)
            {
                originalX = GetX();
                originalY = GetY();
                firstTime = false;
            }

            dragView.DragStarted();

            touchedDown = true;
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            float x = e.RawX;
            float y = e.RawY;

            var dragView = Element as DraggableView;
            var parent = dragView.Parent as xam.View;

            switch (e.Action)
            {
                case MotionEventActions.Down:
                    if (dragView.DragMode == DragModes.Touch)
                    {
                        if (!touchedDown)
                        {
                            if (firstTime)
                            {
                                originalX = GetX();
                                originalY = GetY();
                                firstTime = false;
                            }

                            dragView.DragStarted();
                        }

                        touchedDown = true;
                    }

                    dX = x - this.GetX();
                    dY = y - this.GetY();

                    break;

                case MotionEventActions.Move:
                    if (touchedDown)
                    {
                        var density = global::Xamarin.Essentials.DeviceDisplay.MainDisplayInfo.Density;

                        if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Horizontal)
                        {
                            var newX = x - dX;

                            if (parent != null)
                            {
                                if (newX + Width > parent.Width * density) newX = (float)(parent.Width * density - Width);
                                if (newX < 0) newX = 0;
                            }

                            SetX(newX);
                        }

                        if (dragView.DragDirection == DragDirectionTypes.All || dragView.DragDirection == DragDirectionTypes.Vertical)
                        {
                            var newY = y - dY;

                            if (parent != null)
                            {
                                if (newY + Height > parent.Height * density) newY = (float)(parent.Height * density - Height);
                                if (newY < 0) newY = 0;
                            }

                            SetY(newY);
                        }
                    }

                    break;

                case MotionEventActions.Up:
                    touchedDown = false;

                    DraggableViewDragEndedEventArgs args = new DraggableViewDragEndedEventArgs
                    {
                        X = GetX(),
                        Y = GetY()
                    };

                    dragView.DragEnded(args);

                    break;

                case MotionEventActions.Cancel:
                    touchedDown = false;

                    break;
            }
            return base.OnTouchEvent(e);
        }

        public override bool OnInterceptTouchEvent(MotionEvent e)
        {
            BringToFront();
            return true;
        }
    }
}

这是.Net标准2.0项目中的DraggableView。

    using System;
using System.Windows.Input;
using Xamarin.Forms;

namespace TGB.Xamarin.Forms.Views
{
    public partial class DraggableView : ContentView
    {
        public event EventHandler DragStart = delegate { };

        public delegate void DragEndEventHandler(object sender, DraggableViewDragEndedEventArgs args);

        public event DragEndEventHandler DragEnd;

        public enum DragDirectionTypes
        {
            All,
            Vertical,
            Horizontal
        }

        public enum DragModes
        {
            Touch,
            LongPress
        }

        public static readonly BindableProperty DragDirectionProperty = BindableProperty.Create(
            propertyName: "DragDirection",
            returnType: typeof(DragDirectionTypes),
            declaringType: typeof(DraggableView),
            defaultValue: DragDirectionTypes.All,
            defaultBindingMode: BindingMode.TwoWay);

        public DragDirectionTypes DragDirection
        {
            get { return (DragDirectionTypes)GetValue(DragDirectionProperty); }
            set { SetValue(DragDirectionProperty, value); }
        }


        public static readonly BindableProperty DragModeProperty = BindableProperty.Create(
           propertyName: "DragMode",
           returnType: typeof(DragModes),
           declaringType: typeof(DraggableView),
           defaultValue: DragModes.Touch,
           defaultBindingMode: BindingMode.TwoWay);

        public DragModes DragMode
        {
            get { return (DragModes)GetValue(DragModeProperty); }
            set { SetValue(DragModeProperty, value); }
        }

        public static readonly BindableProperty IsDraggingProperty = BindableProperty.Create(
          propertyName: "IsDragging",
          returnType: typeof(bool),
          declaringType: typeof(DraggableView),
          defaultValue: false,
          defaultBindingMode: BindingMode.TwoWay);

        public bool IsDragging
        {
            get { return (bool)GetValue(IsDraggingProperty); }
            set { SetValue(IsDraggingProperty, value); }
        }

        public static readonly BindableProperty RestorePositionCommandProperty = BindableProperty.Create(nameof(RestorePositionCommand), typeof(ICommand), typeof(DraggableView), default(ICommand), BindingMode.TwoWay, null, OnRestorePositionCommandPropertyChanged);

        static void OnRestorePositionCommandPropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var source = bindable as DraggableView;
            if (source == null)
            {
                return;
            }
            source.OnRestorePositionCommandChanged();
        }

        private void OnRestorePositionCommandChanged()
        {
            OnPropertyChanged("RestorePositionCommand");
        }

        public ICommand RestorePositionCommand
        {
            get
            {
                return (ICommand)GetValue(RestorePositionCommandProperty);
            }
            set
            {
                SetValue(RestorePositionCommandProperty, value);
            }
        }

        public void DragStarted()
        {
            DragStart(this, default);
            IsDragging = true;
        }

        public void DragEnded(DraggableViewDragEndedEventArgs args)
        {

            IsDragging = false;
            DragEnd(this, args);
        }
    }
}

EndDrag中使用的EventArgs类

using System;
using System.Collections.Generic;
using System.Text;

namespace TGB.Xamarin.Forms.Views
{
    public class DraggableViewDragEndedEventArgs : EventArgs
    {
        public double X;
        public double Y;
    }
}

这是Slider类:

using System;
using TGB.Xamarin.Forms.Views;
using Xamarin.Forms;

namespace TGB.Xamarin.Forms.Controls
{
    public class Slider : AbsoluteLayout
    {
        private DraggableView m_Thumb;

        public static readonly BindableProperty MinProperty = BindableProperty.Create(
            "Min", typeof(int), typeof(Slider), 0, propertyChanged: (bindable, oldvalue, newvalue) => { ((Slider)bindable).InvalidateLayout(); });

        /// <summary>
        /// The minimum for the slider
        /// </summary>
        public int Min
        {
            set { SetValue(MinProperty, value); }
            get { return (int)GetValue(MinProperty); }
        }

        public static readonly BindableProperty MaxProperty = BindableProperty.Create(
            "Max", typeof(int), typeof(Slider), 100, propertyChanged: (bindable, oldvalue, newvalue) => { ((Slider)bindable).InvalidateLayout(); });

        /// <summary>
        /// The maximum for the slider
        /// </summary>
        public int Max
        {
            set { SetValue(MaxProperty, value); }
            get { return (int)GetValue(MaxProperty); }
        }

        public static readonly BindableProperty ValueProperty = BindableProperty.Create(
            "Value", typeof(int), typeof(Slider), 100, propertyChanged: (bindable, oldvalue, newvalue) => { ((Slider)bindable).InvalidateLayout(); });

        /// <summary>
        /// The value for the slider
        /// </summary>
        public int Value
        {
            set { SetValue(ValueProperty, value); }
            get { return (int)GetValue(ValueProperty); }
        }

        public Slider()
        {
            BackgroundColor = System.Drawing.Color.Green;

            Init();
        }

        private void Init()
        {
            m_Thumb = new DraggableView();

            m_Thumb.DragEnd += Draggable_DragEnd;

            m_Thumb.HorizontalOptions = new LayoutOptions { Alignment = LayoutAlignment.Fill, Expands = true };

            AbsoluteLayout.SetLayoutBounds(m_Thumb, new Rectangle(0, 0, 1, 0.2));
            AbsoluteLayout.SetLayoutFlags(m_Thumb, AbsoluteLayoutFlags.All);

            m_Thumb.BackgroundColor = System.Drawing.Color.Orange;

            this.Children.Add(m_Thumb);
        }

        private void Draggable_DragEnd(object sender, DraggableViewDragEndedEventArgs e)
        {
            var scope = Max - Min;

            var regionSize = this.Height - m_Thumb.Height;

            var perPixel = scope / regionSize;

            Value = Min + Convert.ToInt32(e.Y * perPixel);
        }
    }
}

这是MainPage.xaml中的实现:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:tgbc="clr-namespace:TGB.Xamarin.Forms.Controls;assembly=TGB.Xamarin.Forms"
             mc:Ignorable="d"
             x:Name="Page"
             x:Class="ElectroSpit.MainPage">

    <ContentPage.Resources>
        <StyleSheet Source="Styles\Styles.css" />
    </ContentPage.Resources>

    <StackLayout x:Name="Main" 
                    Orientation="Vertical"
                    BackgroundColor="Transparent"
                    VerticalOptions="FillAndExpand"
                    HorizontalOptions="FillAndExpand">
        <ContentView x:Name="Sidebar"
                    VerticalOptions="Start"
                    HorizontalOptions="Start"
                    StyleClass="Sidebar">
            <ContentView.Content>
                <Grid VerticalOptions="FillAndExpand" StyleClass="SidebarSlider">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>

                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>

                    <StackLayout Grid.Row="0"
                                 Grid.Column="0"
                                 Orientation="Vertical"
                                 VerticalOptions="FillAndExpand" 
                                 StyleClass="SidebarSlider" >


                         <!-- HERE ARE THE SLIDERS -->


                        <tgbc:Slider x:Name="Pitch"  VerticalOptions="FillAndExpand" StyleClass="SidebarSlider" />
                        <tgbc:Slider x:Name="Tremolo" VerticalOptions="FillAndExpand"  StyleClass="SidebarSlider" />
                    </StackLayout>

                    <StackLayout Grid.Row="0"
                                 Grid.Column="1"
                                 Orientation="Vertical">

                        <Label Text="Trans"  StyleClass="SidebarLabel"/>

                        <StackLayout Orientation="Horizontal">
                            <Button x:Name="TransposeUp" Text="+" StyleClass="SidebarButton"/>
                            <Button x:Name="TransposeDown" Text="{Binding Transposition}" StyleClass="SidebarButton" />
                        </StackLayout>

                        <Label Text="Brightness"  StyleClass="SidebarLabel"/>
                        <Stepper x:Name="Brichtness" Minimum="0" Maximum="100" StyleClass="SidebarStepper"/>
                        <Button x:Name="Settings" Text="Opt" StyleClass="SidebarButton"/>
                        <Label Text="Glide"  StyleClass="SidebarLabel"/>
                        <Stepper x:Name="Glide" Minimum="0" Maximum="100" StyleClass="SidebarStepper"/>
                        <Label Text="Octave" StyleClass="SidebarLabel"/>

                        <StackLayout Orientation="Horizontal">
                            <Button x:Name="OctaveUp" Text="+" StyleClass="SidebarButton"/>

                            <Button x:Name="OctaveDown" Text="{Binding Octave}" StyleClass="SidebarButton"/>
                        </StackLayout>
                    </StackLayout>

                    <StackLayout>
                        <ContentView x:Name="Schema"
                                     BackgroundColor="Transparent"
                                     VerticalOptions="FillAndExpand"
                                     HorizontalOptions="FillAndExpand">
                        </ContentView>
                    </StackLayout>
                </Grid>
            </ContentView.Content>
        </ContentView>
        <ContentView x:Name="Notes"
                        BackgroundColor="Transparent"
                        VerticalOptions="FillAndExpand"
                        HorizontalOptions="FillAndExpand">
        </ContentView>
    </StackLayout>
</ContentPage>

==编辑==

正在运行的应用程序和未运行的应用程序上的消息有所不同。这是我在运行的应用程序上得到的:

05-22 10:29:42.178 D/Mono    ( 6676): DllImport searching in: '__Internal' ('(null)').
05-22 10:29:42.178 D/Mono    ( 6676): Searching for 'java_interop_jnienv_call_float_method_a'.
05-22 10:29:42.178 D/Mono    ( 6676): Probing 'java_interop_jnienv_call_float_method_a'.
05-22 10:29:42.178 D/Mono    ( 6676): Found as 'java_interop_jnienv_call_float_method_a'.
05-22 10:29:42.201 D/Mono    ( 6676): DllImport searching in: '__Internal' ('(null)').
05-22 10:29:42.201 D/Mono    ( 6676): Searching for 'java_interop_jnienv_call_long_method_a'.
05-22 10:29:42.201 D/Mono    ( 6676): Probing 'java_interop_jnienv_call_long_method_a'.
05-22 10:29:42.201 D/Mono    ( 6676): Found as 'java_interop_jnienv_call_long_method_a'.
05-22 10:29:42.260 D/Mono    ( 6676): Requesting loading reference 6 (of 7) of TGB.Xamarin.Forms.Android.dll
05-22 10:29:42.260 D/Mono    ( 6676): Loading reference 6 of TGB.Xamarin.Forms.Android.dll asmctx DEFAULT, looking for Xamarin.Essentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
05-22 10:29:42.260 D/Mono    ( 6676): Assembly Ref addref TGB.Xamarin.Forms.Android[0xd57b8680] -> Xamarin.Essentials[0xebf7fd00]: 3

并且在非正常运行的应用程序上这样:

05-22 09:46:52.254 D/Mono (14307): DllImport searching in: '__Internal' ('(null)'). 
05-22 09:46:52.254 D/Mono (14307): Searching for 'java_interop_jnienv_call_float_method_a'. 
05-22 09:46:52.254 D/Mono (14307): Probing 'java_interop_jnienv_call_float_method_a'. 
05-22 09:46:52.254 D/Mono (14307): Found as 'java_interop_jnienv_call_float_method_a'.
c# android xamarin.forms custom-renderer
1个回答
0
投票

确定,找到了。该控件已经在起作用,我的错误在其他地方。如果仔细观察XAML,您会发现最后一个StackLayout没有Grid.Row和Grid.Column属性,这导致它位于两个Slider的顶部。因此,触摸并不是转到滑块,而是转到StackLayout内的ContentView,给人的印象是它不起作用。

© www.soinside.com 2019 - 2024. All rights reserved.