Surface View 不会显示内容

Surface View will not display content

我们正在尝试学习如何使用动态动画,此代码来自 Github Code 我们尝试了很多更改,但代码什么也没显示。 我们将 post 三个 Class 并且没有 XML 文件包含在 link

我的问题是任何人都可以看出代码中缺少什么或可能有什么问题。 是的,我们已将其包含在 build.gradle

implementation "com.android.support:support-dynamic-animation:26.1.0"

这是主要内容Activity

import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;

/**
* This app demonstrates how to use a SurfaceView to render an image from a
* separate thread.
* In addition, it shows how you can use clipping for animation,
* and implements a basic game loop. This is not intended as a production
* quality app. Rather, it demonstrates the basics
* of these techniques, so you can dive deeper on your own.
*
* Note that SurfaceView offers trade-offs you must consider:
*
* * Offers a lover level drawing surface with more control without the need
* for learning OpenGL or the NDK.
*     * You can draw on it same as a canvas.
*     * Draw from a separate thread, not the UI thread.
*     * Does not have built-in hardware acceleration, e.g. for 
 transformations.
*  Monitor performance carefully, especially if you are doing animations.
*
* Game play:
*
* The user is presented with a dark surface with a white circle.
* This represents a wall shone at with a flashlight cone. Touching the
* surface hides an android image. The light cone then follows continuous
* motion. If the image of an android is discovered, the screen lights up and
* the word "WIN!" appears. To restart lift finger and touch screen again.
*
* The following limitations are imposed to keep the code focused.
*
*     * No startup screen or any other functionality other than game play.
*     * No saving of state, game, or user data.
*     * No acrobatics to handle edge cases.
*/

public class MainActivity extends AppCompatActivity {

private GameView mGameView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Lock orientation into landscape.
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    // Create a GameView and bind it to this activity.
    // You don't need a ViewGroup to fill the screen, because the system
    // has a FrameLayout to which this will be added.
    mGameView = new GameView(this);
    // Android 4.1 and higher simple way to request fullscreen.
    mGameView.setSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN);
    setContentView(mGameView);
    }

   /**
   * Pauses game when activity is paused.
   */
   @Override
  protected void onPause() {
    super.onPause();
    mGameView.pause();
  }

 /**
  * Resumes game when activity is resumed.
  */
 @Override
 protected void onResume() {
    super.onResume();
    mGameView.resume();
  }

还有 FlashlightCone Class

/**
* Cone of flashlight that the user moves around the view.

*/

public class FlashlightCone {

private int mX;
private int mY;
private int mRadius;

public FlashlightCone(int viewWidth, int viewHeight) {
    mX = viewWidth / 2;
    mY = viewHeight / 2;
    // Adjust the radius for the narrowest view dimension.
    mRadius = ((viewWidth <= viewHeight) ? mX / 3 : mY / 3);
 }

/**
 * Update the coordinates of the flashlight cone.
 *
 * @param newX Changed value for x coordinate.
 * @param newY Changed value for y coordinate.
 */
 public void update(int newX, int newY) {
    mX = newX;
    mY = newY;
 }

public int getX() {
    return mX;
}

public int getY() {
    return mY;
}

public int getRadius() {
    return mRadius;
}

和 GameView

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
* This class demonstrates the following interactive game basics:
*
*   * Manages a rendering thread that draws to a SurfaceView.
*   * Basic game loop that sleeps to conserve resources.
*   * Processes user input to update game state.
*   * Uses clipping as a means of animation.
*
* Note that these are basic versions of these techniques.
* Non-fatal edge cases are not handled.
* Error handling is minimal. No logging. App assumes and uses a single 
 thread.
* Additional thread management would otherwise be necessary. See code 
 comments.
*/

public class GameView extends SurfaceView implements Runnable {

private boolean mRunning;
private Thread mGameThread = null;
private Path mPath;

private Context mContext;

private FlashlightCone mFlashlightCone;

private Paint mPaint;
private Bitmap mBitmap;
private RectF mWinnerRect;
private int mBitmapX;
private int mBitmapY;
private int mViewWidth;
private int mViewHeight;
private SurfaceHolder mSurfaceHolder;

public GameView(Context context) {
    this(context, null);
}

public GameView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mContext = context;
    mSurfaceHolder = getHolder();
    mPaint = new Paint();
    mPaint.setColor(Color.DKGRAY);
    mPath = new Path();
}

 /**
  * We cannot get the correct dimensions of views in onCreate because
  * they have not been inflated yet. This method is called every time the
  * size of a view changes, including the first time after it has been
  * inflated.
  *
  * @param w Current width of view.
  * @param h Current height of view.
  * @param oldw Previous width of view.
  * @param oldh Previous height of view.
  */
  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    mViewWidth = w;
    mViewHeight = h;

    mFlashlightCone = new FlashlightCone(mViewWidth, mViewHeight);

    // Set font size proportional to view size.
    mPaint.setTextSize(mViewHeight / 5);

    mBitmap = BitmapFactory.decodeResource(
            mContext.getResources(), R.drawable.android);
    setUpBitmap();
    }

  /**
   * Runs in a separate thread.
   * All drawing happens here.
   */
  public void run() {

    Canvas canvas;

    while (mRunning) {
        // If we can obtain a valid drawing surface...
        if (mSurfaceHolder.getSurface().isValid()) {

            // Helper variables for performance.
            int x = mFlashlightCone.getX();
            int y = mFlashlightCone.getY();
            int radius = mFlashlightCone.getRadius();

            // Lock the canvas. Note that in a more complex app, with
            // more threads, you need to put this into a try/catch block
            // to make sure only one thread is drawing to the surface.
            // Starting with O, you can request a hardware surface with
            //    lockHardwareCanvas().
            // See https://developer.android.com/reference/android/view/
            //    SurfaceHolder.html#lockHardwareCanvas()
            canvas = mSurfaceHolder.lockCanvas();

            // Fill the canvas with white and draw the bitmap.
            canvas.save();
            canvas.drawColor(Color.WHITE);
            canvas.drawBitmap(mBitmap, mBitmapX, mBitmapY, mPaint);

            // Add clipping region and fill rest of the canvas with black.
            mPath.addCircle(x, y, radius, Path.Direction.CCW);
            canvas.clipPath(mPath, Region.Op.DIFFERENCE);
            canvas.drawColor(Color.BLACK);

            // If the x, y coordinates of the user touch are within a
            //  bounding rectangle, display the winning message.
            if (x > mWinnerRect.left && x < mWinnerRect.right
                    && y > mWinnerRect.top && y < mWinnerRect.bottom) {
                canvas.drawColor(Color.WHITE);
                canvas.drawBitmap(mBitmap, mBitmapX, mBitmapY, mPaint);
                canvas.drawText(
                        "WIN!", mViewWidth / 3, mViewHeight / 2, mPaint);
            }
            // Clear the path data structure.
            mPath.rewind();
            // Restore the previously saved (default) clip and matrix state.
            canvas.restore();
            // Release the lock on the canvas and show the surface's
            // contents on the screen.
            mSurfaceHolder.unlockCanvasAndPost(canvas);
         }
     }
   }

   /**
    * Updates the game data.
    * Sets new coordinates for the flashlight cone.
    *
    * @param newX New x position of touch event.
    * @param newY New y position of touch event.
    */
   private void updateFrame(int newX, int newY) {
    mFlashlightCone.update(newX, newY);
   }

   /**
    * Calculates a randomized location for the bitmap
    * and the winning bounding rectangle.
    */
  private void setUpBitmap() {
    mBitmapX = (int) Math.floor(
            Math.random() * (mViewWidth - mBitmap.getWidth()));
    mBitmapY = (int) Math.floor(
            Math.random() * (mViewHeight - mBitmap.getHeight()));
    mWinnerRect = new RectF(mBitmapX, mBitmapY,
            mBitmapX + mBitmap.getWidth(),
            mBitmapY + mBitmap.getHeight());
   }

  /**
   * Called by MainActivity.onPause() to stop the thread.
   */
  public void pause() {
    mRunning = false;
    try {
        // Stop the thread == rejoin the main thread.
        mGameThread.join();
    } catch (InterruptedException e) {
    }
  }

  /**
   * Called by MainActivity.onResume() to start a thread.
   */
  public void resume() {
    mRunning = true;
    mGameThread = new Thread(this);
    mGameThread.start();
  }

   @Override
   public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();

    // Invalidate() is inside the case statements because there are
    // many other motion events, and we don't want to invalidate
    // the view for those.
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            setUpBitmap();
            // Set coordinates of flashlight cone.
            updateFrame((int) x, (int) y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            // Updated coordinates for flashlight cone.
            updateFrame((int) x, (int) y);
            invalidate();
            break;
        default:
            // Do nothing.
      }
       return true;
    }

你想展示什么?我测试了这些代码,我可以显示一个黑色背景和一个用手指移动的白色圆圈。

这个问题不是软件问题,而是您计算机上的硬件和模拟器设置,如果您查看屏幕底部,您会看到这个 模拟器:android/android-emugl/host/libs/Translator/GLES_V2/GLESv2Imp.cpp:glTexSubImage2D:3237 错误 0x500(刚才)

所以 FIX 是通过单击 AVD 管理器打开模拟器 select 您正在测试的模拟器并对图形设置进行此更改 这个软件 GLES 2.0 有什么变化点击完成然后关闭 Android Studio 以确保重新打开使用该模拟器启动您的应用程序并 应用程序会变魔术 运行