You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin Forms中ScrollView内SkiaSharp画布绘图时仍滚动的问题

问题:Android平台Xamarin Forms中ScrollView内SkiaSharp绘图区域滚动干扰问题

在Android平台的Xamarin Forms项目里,我将一个简易SkiaSharp手指绘图区域放置在ScrollView底部,但绘图仅能正常工作很短时间,一旦开始绘图页面就会发生滚动,导致绘制的线条消失,无法完成绘图操作,希望找到解决方法。

相关XAML代码

<ContentPage.Content>
    <ScrollView>
        <StackLayout>
            <Label x:Name="WeatherConditionLabel" Text="Weather/Condition" FontSize="20" FontAttributes="Bold"/>
            <Grid>
                <Label Text="Day/Night:"
                   FontSize="Medium"
           VerticalOptions="Center" />
            </Grid>
            <Switch HorizontalOptions="Start" IsToggled="false" Scale="1.8" Margin="20"/>
            <Grid Margin="20,10,10,20">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.40*" />
                    <ColumnDefinition Width="0.15*" />
                    <ColumnDefinition Width="0.25*" />
                    <ColumnDefinition Width="0.20*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Label Text="Raining:"
                   FontSize="Medium"
           VerticalOptions="Center" />
                <CheckBox GridColumn="1"
              Color="Turquoise"
              VerticalOptions="Center"
              Scale="1.6"
              x:Name="rainingCheck"/>
                <Label GridColumn="2"
           Text="Snowing:"
                   FontSize="Medium"
           VerticalOptions="Center" />
                <CheckBox GridColumn="3"
              Color="Turquoise"
              VerticalOptions="Center" 
              Scale="1.6"
              x:Name="snowingCheck"/>
                <Label GridRow="1"
           Text="Fog/Mist:"
                   FontSize="Medium"
           VerticalOptions="Center" />
                <CheckBox GridRow="1"
              GridColumn="1"
              Color="Turquoise"
              Scale="1.6"
              VerticalOptions="Center"
              x:Name="FogMistCheck"/>
            </Grid>
            <Label x:Name="VehicleConditionImageLabel" Text="Vehicle Condition" FontSize="20" FontAttributes="Bold"/>
            <xct:DrawingView x:Name="damageDrawing" HeightRequest="200" DefaultLineColor="green" ClearOnFinish="False" ></xct:DrawingView>
            <Grid Margin="5,5,5,5">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="35*" />
                    <ColumnDefinition Width="30*" />
                    <ColumnDefinition Width="35*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="40" />
                </Grid.RowDefinitions>
                <Button x:Name="greenBtn" VerticalOptions="Center" BackgroundColor="Green" />
                <Button GridColumn="1" x:Name="amberBtn" VerticalOptions="Center" BackgroundColor="Yellow" />
                <Button GridColumn="2" x:Name="rebBtn" VerticalOptions="Center" BackgroundColor="red" Clicked="redBtnPressed" />
            </Grid>

            <Grid BackgroundColor="White">
                <skia:SKCanvasView x:Name="canvasView"
                       HeightRequest="200"            
                       PaintSurface="OnCanvasViewPaintSurface" />
                <Grid.Effects>
                    <tt:TouchEffect Capture="True"
                        TouchAction="OnTouchEffectAction" />
                </Grid.Effects>
            </Grid>
        </StackLayout>
    </ScrollView>
</ContentPage.Content>

解决方法

方法1:拦截触摸事件,阻止ScrollView响应滚动

在触摸绘图区域时,让触摸事件优先被绘图区域处理,不传递给ScrollView。修改OnTouchEffectAction方法,标记事件已处理:

void OnTouchEffectAction(object sender, TouchActionEventArgs e)
{
    // 执行你的绘图逻辑(比如记录触摸点、绘制线条等)
    
    // 阻止事件继续传递给ScrollView,避免触发滚动
    e.Handled = true;
}

方法2:临时禁用ScrollView滚动

在开始绘图时禁用ScrollView,结束后恢复:

  1. 先给ScrollView命名:
<ScrollView x:Name="MainScrollView">
    <!-- 原有内容 -->
</ScrollView>
  1. 修改触摸事件处理代码:
void OnTouchEffectAction(object sender, TouchActionEventArgs e)
{
    switch (e.Type)
    {
        case TouchActionType.Pressed:
            // 开始绘图,禁用ScrollView滚动
            MainScrollView.IsEnabled = false;
            // 绘图逻辑...
            break;
        case TouchActionType.Released:
        case TouchActionType.Cancelled:
            // 绘图结束,恢复ScrollView滚动
            MainScrollView.IsEnabled = true;
            // 绘图逻辑...
            break;
        case TouchActionType.Moved:
            // 处理移动绘图逻辑...
            break;
    }
}

方法3:自定义ScrollView渲染器(Android端)

如果前两种方法效果不佳,可通过自定义渲染器在Android层面拦截滚动:

  1. 创建自定义ScrollView类:
public class CustomScrollView : ScrollView
{
    public bool IsScrollEnabled { get; set; } = true;
}
  1. 在Android项目中添加渲染器:
[assembly: ExportRenderer(typeof(CustomScrollView), typeof(CustomScrollViewRenderer))]
namespace YourAppNamespace.Droid.Renderers
{
    public class CustomScrollViewRenderer : ScrollViewRenderer
    {
        public CustomScrollViewRenderer(Context context) : base(context) { }

        protected override void OnElementChanged(ElementChangedEventArgs<ScrollView> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement is CustomScrollView customScrollView)
            {
                customScrollView.PropertyChanged += (s, args) =>
                {
                    if (args.PropertyName == nameof(CustomScrollView.IsScrollEnabled))
                    {
                        Enabled = customScrollView.IsScrollEnabled;
                    }
                };
            }
        }

        // 可选:拦截触摸事件,判断是否在绘图区域内再决定是否允许滚动
        public override bool OnInterceptTouchEvent(MotionEvent ev)
        {
            if (Element is CustomScrollView customScrollView && !customScrollView.IsScrollEnabled)
            {
                return false; // 不拦截,让子控件处理
            }
            return base.OnInterceptTouchEvent(ev);
        }
    }
}
  1. 在XAML中替换原有ScrollView:
<local:CustomScrollView x:Name="MainScrollView">
    <!-- 原有内容 -->
</local:CustomScrollView>
  1. 在触摸事件中控制滚动状态:
void OnTouchEffectAction(object sender, TouchActionEventArgs e)
{
    switch (e.Type)
    {
        case TouchActionType.Pressed:
            MainScrollView.IsScrollEnabled = false;
            // 绘图逻辑...
            break;
        case TouchActionType.Released:
        case TouchActionType.Cancelled:
            MainScrollView.IsScrollEnabled = true;
            // 绘图逻辑...
            break;
    }
}

内容的提问来源于stack exchange,提问作者TryingAgain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:07:03