如何创建像Facebook信使聊天一样的反弹泡泡系统窗口叠加

时间:2014-09-19 05:16:25

标签: android bounce

我是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();
                }
            }
        });
    }
   }


 }

0 个答案:

没有答案