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.CoreNuGet包才能使用ContextCompat.GetDrawable - 如果你的图片放在不同分辨率的drawable文件夹(比如drawable-hdpi、drawable-xhdpi),系统会自动根据设备屏幕密度选择合适的版本,无需手动处理
- 要是需要对Bitmap进行裁剪、缩放等操作,必须先正确加载原始Bitmap,再用
Bitmap.CreateBitmap进行二次处理
内容的提问来源于stack exchange,提问作者ContemplativeCyborg




