Как нарисовать векторную графику на холсте SurfaceView?

#android #canvas #drawable

#Android #холст #возможность рисования

Вопрос:

Моя активность имеет setContentView с классом SurfaceView. Теперь я безуспешно пытаюсь нарисовать векторную графику на этом холсте SurfaceView, я вижу только черный экран.

Итак, у меня есть немного векторной графики в XML-файле — R.drawable.battery. Он правильно отображается в окне предварительного просмотра Android Studio.

 public class BoardActivity extends Activity {
MySurfaceView mySurface; // My surfaceview class
Drawable vd;
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mySurface = new MySurfaceView(this);
       vd = ContextCompat.getDrawable(getApplicationContext(), R.drawable.battery);
        setContentView(mySurface);

public class MySurfaceView extends SurfaceView implements Runnable{
 Thread t;
 SurfaceHolder holder;
 boolean isItOK = false;

public MySurfaceView(Context context) {
  super(context);
  holder = getHolder(); 
  resume();
}

@Override
public void run() {
  while(isItOK==true) {
   if(!holder.getSurface().isValid()) {
       continue;
   }
  Canvas canvas = holder.lockCanvas();
  canvas .drawARGB(80, 188, 230, 227 ); 
  vd.draw(canvas); // draw nothing! 

  // canvas.drawRect(...   works perfect! The issue is only with vd.draw(canvas); 
  holder.unlockCanvasAndPost(c);
}

  public void pause() {
        isItOK = false;
        while(true) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            break;
        }
        t = null;
    }


    public void resume(){
        isItOK = true; //Starting drawing 
        t = new Thread(this);
        t.start();
    }    
}
  

Ответ №1:

Я новичок в Android, поэтому я действительно не знаю, является ли то, что я покажу вам, хорошей практикой, но вот она:

 import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.SurfaceView;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final Drawable d = getResources().getDrawable(R.drawable.battery, null);
        final SurfaceView view = new SurfaceView(this) {
            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                d.draw(canvas);
            }
        };
        view.setBackgroundColor(Color.WHITE);
        setContentView(view);
    }
}
  

Этот код работает для меня.

Важно: вы установили цвет фона на белый? Если нет, то я думаю, что не нужно, и если ваш холст будет отображаться правильно в дизайн вкладки в Андроид-студии, то я думаю, что это должно работать в вашем приложении тоже.

В качестве альтернативы (и может быть лучше) вы можете рассмотреть ImageView , а также добавить ее в файл ресурсов макета. Например, основной код действия может стать:

 import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
  

а затем в res/layout/activity_main.xml поместить:

 <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@ id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/battery"
        android:contentDescription="@string/batteryDesc" />
</androidx.constraintlayout.widget.ConstraintLayout>
  

Не забудьте добавить batteryDesc именованную константу в res/values/strings.xml .

Комментарии:

1. Привет, gthanop! Спасибо, это работает, но это статично. Но у меня есть SurfaceView в отдельном потоке и запущен метод run () для обновления экрана со скоростью обновления 60 кадров в секунду (это классический игровой шаблон). Таким образом, d.draw (canvas) не работает.

2. Привет. Я думаю, вам следует опубликовать весь свой код в вашем вопросе (в основном код вашей активности и Thread ), чтобы другие могли понять, что вы ищете. Почему это не d.draw(canvas); не работает? Создавали ли вы подкласс, SurfaceView чтобы переопределить его onDraw и нарисовать там изображение? Что еще нарисовано на SurfaceView ? На все эти вопросы можно получить ответы, если вы предоставите как можно больше кода вашего приложения внутри вашего вопроса. Работает ли ваша программа для рисования? Опубликуйте это также в вопросе. Аннулирование представления каждые 16 мс не означает, что вы не можете переопределить SurfaceView.onDraw для drawable

3. переопределение onDraw () также мне не помогло. Я нашел решение в преобразовании моего изображения в растровое изображение с помощью bitmap = Bitmap.CreateBitmap (векторное изображение.getIntrinsicWidth(), векторное изображение.getIntrinsicHeight (), Bitmap.Config. ARGB_8888); canvas = new Canvas(bitmap); VectorImage.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); VectorImage.draw(canvas); и затем применяем canvas.drawBitmap(bitmap, 0, 0, null); в методе run() SurfaceView. Это действительно странный обходной путь.

4. Если вы нашли ответ самостоятельно, то вы можете ответить на свой собственный вопрос и принять его по истечении определенного количества времени. Если вам нужна дополнительная помощь, вы можете следовать инструкциям, которые я вам уже дал (т. Е. Опубликовать код ваших классов в вопросе), а также ответить на мои вопросы, если это возможно. Лично я не думаю, что есть необходимость в этом обходном пути, но это всего лишь мое мнение. Если вы опубликуете свой код в своем вопросе, то мы могли бы предложить решение вашей проблемы, но я не думаю, что вы сможете получить лучшую помощь, чем с помощью кода, опубликованного в вашем вопросе. Обходной путь.

5. Я обновил первоначальный вопрос более или менее полной настройкой кода! Пожалуйста, проверьте это.