我是android开发者。我创建系统窗口叠加。我想反弹泡泡只留下左上角,右上角,左下角。底部右角。你从右上角拉伸球到中心然后球直接反弹右上角.ball只留下像Facebook使者那样的四个角落。我也尝试了几天,但我不知道这样做。我的代码中有任何一个,请告诉我们这段代码有什么变化。
package com.example.bubble;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.IBinder;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.RelativeLayout;
@SuppressWarnings("deprecation")
public class PlayerService extends Service
{
private static final int HIDDEN_FRACTION = 20; // Controls fraction of the tray hidden when open
private static final int MOVEMENT_REGION_FRACTION = 20; // Controls fraction of y-axis on screen within which the tray stays.
private static final int VIEW_CROP_FRACTION = 12; // Controls fraction of the tray chipped at the right end.
private static final int ANIMATION_FRAME_RATE = 30; // Animation frame rate per second.
private static final int VIEW_DIM_X_DP = 170; // Width of the tray in dps
private static final int VIEW_DIM_Y_DP = 170; // Height of the tray in dps
// Layout containers for various widgets
private WindowManager mWindowManager; // Reference to the window
private WindowManager.LayoutParams mWindowParams; // Parameters of the root layout
private RelativeLayout mRootLayout; // Root layout
private RelativeLayout mCoverLayout; // Contains album cover of the active song
// Variables that control drag
private int mStartDragX;
//private int mStartDragY; // Unused as yet
private int mPrevDragX;
private int mPrevDragY;
private boolean mIsTrayOpen = true;
// Controls for animations
private Timer mTrayAnimationTimer;
private TrayAnimationTimerTask mTrayTimerTask;
private Handler mAnimationHandler = new Handler();
@Override
public IBinder onBind(Intent intent) {
// Not used
return null;
}
@Override
public void onCreate() {
// Get references to all the views and add them to root view as needed.
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mRootLayout = (RelativeLayout) LayoutInflater.from(this).
inflate(R.layout.service_player, null);
mCoverLayout = (RelativeLayout) mRootLayout.findViewById(R.id.cover_layout);
mCoverLayout.setOnTouchListener(new TrayTouchListener());
mWindowParams = new WindowManager.LayoutParams(
Utils.dpToPixels(VIEW_DIM_X_DP, getResources()),
Utils.dpToPixels(VIEW_DIM_Y_DP, getResources()),
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
mWindowManager.addView(mRootLayout, mWindowParams);
// Post these actions at the end of looper message queue so that the layout is
// fully inflated once these functions execute
mRootLayout.postDelayed(new Runnable() {
@Override
public void run() {
// Reusable variables
RelativeLayout.LayoutParams params;
InputStream is;
Bitmap bmap;
int containerNewWidth = (VIEW_CROP_FRACTION-1)*mCoverLayout.getHeight()/VIEW_CROP_FRACTION;
// Setup background album cover
is=null;
try {
//is = getAssets().open(mPlaylist.getCurrentSongInfo().mAlbumCoverPath);
is=getAssets().open("adele.png");
} catch (IOException e) {
e.printStackTrace();
}
bmap = Utils.loadMaskedBitmap(is, mCoverLayout.getHeight(), containerNewWidth);
params = (RelativeLayout.LayoutParams) mCoverLayout.getLayoutParams();
params.width = (bmap.getWidth() * mCoverLayout.getHeight()) / bmap.getHeight();
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,0);
mCoverLayout.setLayoutParams(params);
mCoverLayout.requestLayout();
mCoverLayout.setBackgroundDrawable(new BitmapDrawable(getResources(), bmap));
// Setup the root layout
mWindowParams.x = -mCoverLayout.getLayoutParams().width;
mWindowParams.y = (getApplicationContext().getResources().getDisplayMetrics().heightPixels-mRootLayout.getHeight()) / 2;
mWindowManager.updateViewLayout(mRootLayout, mWindowParams);
// Make everything visible
mRootLayout.setVisibility(View.VISIBLE);
// Animate the Tray
mTrayTimerTask = new TrayAnimationTimerTask();
mTrayAnimationTimer = new Timer();
mTrayAnimationTimer.schedule(mTrayTimerTask, 0, ANIMATION_FRAME_RATE);
}
}, ANIMATION_FRAME_RATE);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getBooleanExtra("stop_service", false)){
// If it's a call from the notification, stop the service.
stopSelf();
}else{
// Make the service run in foreground so that the system does not shut it down.
Intent notificationIntent = new Intent(this, PlayerService.class);
notificationIntent.putExtra("stop_service", true);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, notificationIntent, 0);
Notification notification = new Notification(
R.drawable.ic_launcher,
"Spotify tray launched",
System.currentTimeMillis());
notification.setLatestEventInfo(
this,
"Spotify tray",
"Tap to close the widget.",
pendingIntent);
startForeground(86, notification);
}
return START_STICKY;
}
// The app is closing.
@Override
public void onDestroy() {
if (mRootLayout != null)
mWindowManager.removeView(mRootLayout);
}
// Drags the tray as per touch info
private void dragTray(int action, int x, int y){
switch (action){
case MotionEvent.ACTION_DOWN:
// Cancel any currently running animations/automatic tray movements.
if (mTrayTimerTask!=null){
mTrayTimerTask.cancel();
mTrayAnimationTimer.cancel();
}
// Store the start points
mStartDragX = x;
//mStartDragY = y;
mPrevDragX = x;
mPrevDragY = y;
break;
case MotionEvent.ACTION_MOVE:
// Calculate position of the whole view according to the drag, and update layout.
float deltaX = x-mPrevDragX;
float deltaY = y-mPrevDragY;
mWindowParams.x += deltaX;
mWindowParams.y += deltaY;
mPrevDragX = x;
mPrevDragY = y;
mWindowManager.updateViewLayout(mRootLayout, mWindowParams);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// When the view is released, bring it back to "open" or "closed" state.
if ((mIsTrayOpen && (x-mStartDragX)<=0) ||
(!mIsTrayOpen && (x-mStartDragX)>=0))
mIsTrayOpen = !mIsTrayOpen;
mTrayTimerTask = new TrayAnimationTimerTask();
mTrayAnimationTimer = new Timer();
mTrayAnimationTimer.schedule(mTrayTimerTask, 0, ANIMATION_FRAME_RATE);
break;
}
}
// Listens to the touch events on the tray.
private class TrayTouchListener implements OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Filter and redirect the events to dragTray()
dragTray(action, (int)event.getRawX(), (int)event.getRawY());
break;
default:
return false;
}
return true;
}
}
// Timer for animation/automatic movement of the tray.
private class TrayAnimationTimerTask extends TimerTask{
// Ultimate destination coordinates toward which the tray will move
int mDestX;
int mDestY;
public TrayAnimationTimerTask(){
// Setup destination coordinates based on the tray state.
super();
if (!mIsTrayOpen){
mDestX = -mCoverLayout.getWidth();
}else{
mDestX = -mRootLayout.getWidth()/HIDDEN_FRACTION;
}
// Keep upper edge of the widget within the upper limit of screen
int screenHeight = getResources().getDisplayMetrics().heightPixels;
mDestY = Math.max(
screenHeight/MOVEMENT_REGION_FRACTION,
mWindowParams.y);
// Keep lower edge of the widget within the lower limit of screen
mDestY = Math.min(
((MOVEMENT_REGION_FRACTION-1)*screenHeight)/MOVEMENT_REGION_FRACTION - mRootLayout.getWidth(),
mDestY);
mDestX = Math.max(mWindowParams.x,screenHeight/MOVEMENT_REGION_FRACTION);
// Keep lower edge of the widget within the lower limit of screen
mDestX = Math.min(mDestX,((MOVEMENT_REGION_FRACTION-1)*screenHeight)/MOVEMENT_REGION_FRACTION - mRootLayout.getWidth());
}
// This function is called after every frame.
@Override
public void run() {
// handler is used to run the function on main UI thread in order to
// access the layouts and UI elements.
mAnimationHandler.post(new Runnable() {
@Override
public void run() {
// Update coordinates of the tray
mWindowParams.x = (2*(mWindowParams.x-mDestX))/3 + mDestX;
mWindowParams.y = (2*(mWindowParams.y-mDestY))/3 + mDestY;
mWindowManager.updateViewLayout(mRootLayout, mWindowParams);
// Cancel animation when the destination is reached
if (Math.abs(mWindowParams.x-mDestX)<2 && Math.abs(mWindowParams.y-mDestY)<2){
TrayAnimationTimerTask.this.cancel();
mTrayAnimationTimer.cancel();
}
}
});
}
}
}