You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Xamarin.Android Canvas绘制Bitmap遇资源空引用问题求助

在Xamarin.Android的Canvas上绘制Bitmap/Drawable的正确方法

我太懂你这种感受了——找Java的Android绘图示例一抓一大把,但Xamarin/C#的相关内容少得可怜,还踩了资源加载的坑,要么编译报错要么空引用崩溃。别着急,我帮你把问题拆解清楚,一步步解决。

先揪出你代码里的核心问题

你之前的尝试失败主要是这几个原因:

  • 你声明的res变量根本没初始化,空着就传给BitmapFactory.DecodeResource,肯定会触发空引用异常
  • 直接用本地电脑的路径加载图片是完全错误的——Android应用运行时处于沙箱环境,访问不到你电脑的本地路径
  • canvas.SetBitmap是用来指定Canvas要绘制的目标Bitmap,不是用来把Bitmap画到Canvas上的,属于方法误用

正确实现步骤(附修改后的完整代码)

第一步:确保资源文件配置正确

先检查你的green.jpg是不是放在Resources/drawable文件夹下,然后右键这个文件→属性,把「生成操作」设置为AndroidResource——这一步非常关键,不设置的话编译器根本不会把它当成应用资源打包进去。

第二步:修改你的MyCanvasPath

下面是修复后的完整代码,我标注了关键修改点:

class MyCanvasPath : Android.Views.View
{
    Paint myPaint = new Paint();
    Color myColor = new Color();
    Path myPath = new Path();
    // 1. 正确声明Bitmap变量
    private Bitmap _bitmap;
    // 如果想用Drawable的话,也可以声明这个变量
    private Drawable _drawable;

    public MyCanvasPath(Context context) : base(context)
    {
        // 2. 用Context的Resources加载Bitmap,这才是Xamarin里正确的资源加载方式
        _bitmap = BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.green);
        // 如果想用Drawable替代Bitmap,用下面这行(需要引用AndroidX.Core.Content命名空间)
        // _drawable = ContextCompat.GetDrawable(context, Resource.Drawable.green);

        int[,] FirstPath = new int[,] { { 200, 350 }, { 70, 80 }, { 90, 40 }, { 10, 40 }, { 50, 80 }, { 0, 350 } };
        int arrayLength = FirstPath.Length / 2;

        myPaint.SetARGB(255, 200, 255, 0);
        myPaint.SetStyle(Paint.Style.FillAndStroke);
        myPaint.StrokeWidth = 9;
        myPaint.TextSize = 40;
        myPaint.Color = Color.DarkCyan;

        myColor = Color.RosyBrown;

        myPath.Reset();
        myPath.MoveTo(FirstPath[0, 0], FirstPath[0, 1]);
        for (int tempint = 1; tempint < arrayLength; tempint++)
        {
            myPath.LineTo(FirstPath[tempint, 0], FirstPath[tempint, 1]);
        }
    }

    protected override void OnDraw(Canvas canvas)
    {
        canvas.DrawColor(myColor);
        int b = canvas.Height;
        int a = canvas.Width;
        canvas.DrawText($"{b} x {a}", 10, b - 50, myPaint);
        canvas.DrawPath(myPath, myPaint);

        // 3. 绘制Bitmap到Canvas上,先判空避免空引用
        if (_bitmap != null)
        {
            // 参数分别是:Bitmap对象、左上角X坐标、左上角Y坐标、Paint(传null用默认设置即可)
            canvas.DrawBitmap(_bitmap, 100, 100, myPaint);
        }

        // 如果用Drawable的话,替换成下面这段代码
        /*
        if (_drawable != null)
        {
            // 先设置Drawable的显示区域(左、上、右、下边界)
            _drawable.SetBounds(100, 100, 100 + _drawable.IntrinsicWidth, 100 + _drawable.IntrinsicHeight);
            _drawable.Draw(canvas);
        }
        */
    }

    // 4. 记得回收Bitmap/释放Drawable,避免内存泄漏(可选但推荐)
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (disposing)
        {
            _bitmap?.Recycle();
            _drawable?.Dispose();
        }
    }
}

额外注意事项

  • 如果你使用AndroidX库,需要确保引用了AndroidX.Core NuGet包才能使用ContextCompat.GetDrawable
  • 如果你的图片放在不同分辨率的drawable文件夹(比如drawable-hdpi、drawable-xhdpi),系统会自动根据设备屏幕密度选择合适的版本,无需手动处理
  • 要是需要对Bitmap进行裁剪、缩放等操作,必须先正确加载原始Bitmap,再用Bitmap.CreateBitmap进行二次处理

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

火山引擎 最新活动