当我的应用程序尝试创建新的气泡时,我遇到了错误。
我在那个框架中有一个框架有一个自定义视图,当我触摸一个空白区域时,当用户触摸一个气泡时,它会创建一个新的气泡,气泡就会消失并播放一个流行音。
这是我的代码:
public class BubbleActivity extends Activity {
// These variables are for testing purposes, do not modify
private final static int RANDOM = 0;
private final static int SINGLE = 1;
private final static int STILL = 2;
private static int speedMode = RANDOM;
private static final String TAG = "Lab-Graphics";
// The Main view
private RelativeLayout mFrame;
// Bubble image's bitmap
private Bitmap mBitmap;
// Display dimensions
private int mDisplayWidth, mDisplayHeight;
// Sound variables
// AudioManager
private AudioManager mAudioManager;
// SoundPool
private SoundPool mSoundPool;
// ID for the bubble popping sound
private int mSoundID;
// Audio volume
private float mStreamVolume;
BubbleView bubbleView;
// Gesture Detector
private GestureDetector mGestureDetector;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Set up user interface
mFrame = (RelativeLayout) findViewById(R.id.frame);
// Load basic bubble Bitmap
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.b64);
}
@Override
protected void onResume() {
super.onResume();
// Manage bubble popping sound
// Use AudioManager.STREAM_MUSIC as stream type
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
mStreamVolume = (float) mAudioManager
.getStreamVolume(AudioManager.STREAM_MUSIC)
/ mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
// TODO - make a new SoundPool, allowing up to 10 streams
mSoundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
// TODO - set a SoundPool OnLoadCompletedListener that calls
// setupGestureDetector()
mSoundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId,
int status) {
if (0 == status) {
setupGestureDetector();
} else {
Log.i(TAG, "Unable to load sound");
finish();
}
}
});
// TODO - load the sound from res/raw/bubble_pop.wav
mAudioManager.loadSoundEffects();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
// Get the size of the display so this View knows where borders are
mDisplayWidth = mFrame.getWidth();
mDisplayHeight = mFrame.getHeight();
}
}
// Set up GestureDetector
private void setupGestureDetector() {
mGestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
// If a fling gesture starts on a BubbleView then change the
// BubbleView's velocity
@Override
public boolean onFling(MotionEvent event1,
MotionEvent event2, float velocityX, float velocityY) {
// TODO - Implement onFling actions.
// You can get all Views in mFrame one at a time
// using the ViewGroup.getChildAt() method
if (bubbleView.intersects(velocityX, velocityY)) {
bubbleView.deflect(velocityX,velocityY);
}
return true;
}
// If a single tap intersects a BubbleView, then pop the
// BubbleView
// Otherwise, create a new BubbleView at the tap's location
// and add
// it to mFrame. You can get all views from mFrame with
// ViewGroup.getChildAt()
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
// TODO - Implement onSingleTapConfirmed actions.
// You can get all Views in mFrame using the
// ViewGroup.getChildCount() method
mFrame.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
float pointerX = event.getX();
float pointerY = event.getY();
int pointerIndex = event.getActionIndex();
int pointerID = event.getPointerId(pointerIndex);
if (bubbleView.intersects(pointerX,pointerY)) {
bubbleView = (BubbleView) mFrame.getChildAt(pointerID);
bubbleView.stopMovement(true);
} else {
bubbleView = new BubbleView(
getApplicationContext(),
mBitmap);
mFrame.addView(bubbleView);
}
}
return true;
}
});
return true;
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO - Delegate the touch to the gestureDetector
return mGestureDetector.onTouchEvent(event);
}
@Override
protected void onPause() {
// TODO - Release all SoundPool resources
if (null != mSoundPool) {
mSoundPool.unload(mSoundID);
mSoundPool.release();
mSoundPool = null;
}
mAudioManager.setSpeakerphoneOn(false);
mAudioManager.unloadSoundEffects();
super.onPause();
}
// BubbleView is a View that displays a bubble.
// This class handles animating, drawing, and popping amongst other actions.
// A new BubbleView is created for each bubble on the display
public class BubbleView extends View {
private static final int BITMAP_SIZE = 64;
private static final int REFRESH_RATE = 40;
private final Paint mPainter = new Paint();
private ScheduledFuture<?> mMoverFuture;
private int mScaledBitmapWidth;
private Bitmap mScaledBitmap;
// location, speed and direction of the bubble
private float mXPos, mYPos, mDx, mDy, mRadius, mRadiusSquared;
private long mRotate, mDRotate;
BubbleView(Context context, float x, float y) {
super(context);
// Create a new random number generator to
// randomize size, rotation, speed and direction
Random r = new Random();
// Creates the bubble bitmap for this BubbleView
createScaledBitmap(r);
// Radius of the Bitmap
mRadius = mScaledBitmapWidth / 2;
mRadiusSquared = mRadius * mRadius;
// Adjust position to center the bubble under user's finger
mXPos = x - mRadius;
mYPos = y - mRadius;
// Set the BubbleView's speed and direction
setSpeedAndDirection(r);
// Set the BubbleView's rotation
setRotation(r);
mPainter.setAntiAlias(true);
}
public BubbleView(Context applicationContext, Bitmap mBitmap) {
// TODO Auto-generated constructor stub
super(getBaseContext());
}
private void setRotation(Random r) {
if (speedMode == RANDOM) {
// TODO - set rotation in range [1..3]
mDRotate = r.nextInt(3);
//mDRotate = r.nextInt(n)
} else {
mDRotate = 0;
}
}
private void setSpeedAndDirection(Random r) {
// Used by test cases
switch (speedMode) {
case SINGLE:
mDx = 20;
mDy = 20;
break;
case STILL:
// No speed
mDx = 0;
mDy = 0;
break;
default:
// TODO - Set mDx and mDy to indicate movement direction and
// speed
// Limit speed in the x and y direction to [-3..3] pixels per
// movement.
}
}
private void createScaledBitmap(Random r) {
if (speedMode != RANDOM) {
mScaledBitmapWidth = BITMAP_SIZE * 3;
} else {
// TODO - set scaled bitmap size in range [1..3] * BITMAP_SIZE
mScaledBitmapWidth = r.nextInt(3)*BITMAP_SIZE;
}
// TODO - create the scaled bitmap using size set above
mBitmap.createScaledBitmap(mScaledBitmap, mDisplayWidth, mDisplayHeight, false);
}
// Start moving the BubbleView & updating the display
private void startMovement() {
// Creates a WorkerThread
ScheduledExecutorService executor = Executors
.newScheduledThreadPool(1);
// Execute the run() in Worker Thread every REFRESH_RATE
// milliseconds
// Save reference to this job in mMoverFuture
mMoverFuture = executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
// TODO - implement movement logic.
// Each time this method is run the BubbleView should
// move one step. If the BubbleView exits the display,
// stop the BubbleView's Worker Thread.
// Otherwise, request that the BubbleView be redrawn.
if(!isOutOfView()){
moveWhileOnScreen();
}
else{
stopMovement(true);
}
}
}, 0, REFRESH_RATE, TimeUnit.MILLISECONDS);
}
// Returns true if the BubbleView intersects position (x,y)
private synchronized boolean intersects(float x, float y) {
// TODO - Return true if the BubbleView intersects position (x,y)
if ( (x>mXPos && x<(mXPos+mScaledBitmapWidth)) && (y>mYPos && y<(mYPos+mScaledBitmapWidth)) ) {
return true;
}
return false;
}
// Cancel the Bubble's movement
// Remove Bubble from mFrame
// Play pop sound if the BubbleView was popped
private void stopMovement(final boolean wasPopped) {
if (null != mMoverFuture) {
if (!mMoverFuture.isDone()) {
mMoverFuture.cancel(true);
}
// This work will be performed on the UI Thread
mFrame.post(new Runnable() {
@Override
public void run() {
// TODO - Remove the BubbleView from mFrame
mFrame.removeView(BubbleView.this);
// TODO - If the bubble was popped by user,
// play the popping sound
if (wasPopped) {
mSoundPool.play(mSoundID, 1, 1, 1, 0, 1);
}
}
});
}
}
// Change the Bubble's speed and direction
private synchronized void deflect(float velocityX, float velocityY) {
mDx = velocityX / REFRESH_RATE;
mDy = velocityY / REFRESH_RATE;
}
// Draw the Bubble at its current location
@Override
protected synchronized void onDraw(Canvas canvas) {
// TODO - save the canvas
canvas.save();
// TODO - increase the rotation of the original image by mDRotate
mRotate = mRotate + mDRotate;
// TODO Rotate the canvas by current rotation
// Hint - Rotate around the bubble's center, not its position
canvas.rotate(mRotate, mXPos + mScaledBitmapWidth/2, mYPos + mScaledBitmapWidth/2);
// TODO - draw the bitmap at it's new location
canvas.drawBitmap(mScaledBitmap, mXPos, mYPos,mPainter);
// TODO - restore the canvas
canvas.restore();
}
// Returns true if the BubbleView is still on the screen after the move
// operation
private synchronized boolean moveWhileOnScreen() {
// TODO - Move the BubbleView
mXPos = mDx+mXPos;
mYPos = mDy+mYPos;
postInvalidate();
return isOutOfView();
}
// Return true if the BubbleView is still on the screen after the move
// operation
private boolean isOutOfView() {
// TODO - Return true if the BubbleView is still on the screen after
// the move operation
if(mXPos + mScaledBitmapWidth/2 >= mDisplayWidth - mScaledBitmapWidth/2 || mXPos <0
||mYPos + mScaledBitmapWidth/2 >= mDisplayHeight - mScaledBitmapWidth/2 || mYPos <0){
return true;
}
return false;
}
}
这是Logcat MSG:
答案 0 :(得分:0)
这是因为您没有在代码中的任何位置创建BubbleView实例。由于您要在点击时添加气泡,请修改onSingleTapConfirmed()
,如下所示:
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
// TODO - Implement onSingleTapConfirmed actions.
// You can get all Views in mFrame using the
// ViewGroup.getChildCount() method
boolean createBubble = true;
float x = event.getX();
float y = event.getY();
for(int i = 0 ; i < mFrame.getChildCount(); i++){
BubbleView view = (BubbleView) mFrame.getChildAt(i);
if(view.intersects(x, y)){
view.stopMovement(true);
createBubble = false;
}
}
if(createBubble){
BubbleView bv = new BubbleView(getApplicationContext(), x, y);
mFrame.addView(bv);
}
return true;
}
});
}