SurfaceView在PopupWindow中无法正常工作

时间:2013-12-16 10:43:05

标签: android surfaceview popupwindow surfaceholder

我将根据三星SPen的AirView功能使用PopupWindow显示预览

但问题是没有创建SurfaceView而且没有调用SurfaceHolder.Callback方法。

显示弹出窗口时,表面区域变为透明,因为根本不会创建表面。

SurfaceView 未创建且透明:

enter image description here

HoverPreview

public class HoverPreview extends LinearLayout implements View.OnHoverListener, SurfaceHolder.Callback {
    private static final String TAG = "HoverPreview";
    private SurfaceHolder mHolder = null;
    View mAnchorView = null;
    String videoPath;
    int position;
    private boolean IsMediaPlayerReady = false;
    private MediaPlayer mMediaPlayer;
    private SurfaceView mSurfaceView;
    Context context;

    public HoverPreview(Context context, String videoPath, int position) {
        super(context);
        this.videoPath = videoPath;
        this.position = position;
        setupLayout(context);
    }

    public HoverPreview(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupLayout(context);
    }

    public HoverPreview(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setupLayout(context);
    }

    private void setupLayout(Context context) {
        this.context = context;
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.media_browser_hover, this);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        Log.d(TAG, "HoverSurface created");

        final Surface surface = surfaceHolder.getSurface();
        if (surface == null) return;
        if (!surface.isValid()) return;

        mHolder = surfaceHolder;

        mMediaPlayer = new MediaPlayer();

        try {
            mMediaPlayer.setDataSource(videoPath);
        } catch (IOException e) {
            e.printStackTrace();
        }

        mMediaPlayer.setDisplay(mHolder);
        mAnchorView.setTag(mMediaPlayer);

        mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
            @Override
            public void onVideoSizeChanged(MediaPlayer mediaPlayer, int i, int i2) {
                mHolder.setFixedSize(i, i2);
            }
        });

        mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mediaPlayer) {
                Log.d(TAG, "MediaPlayer preview is prepared");
                IsMediaPlayerReady = true;

                if (mMediaPlayer != null && IsMediaPlayerReady) {
                    if (position > 0)
                        mMediaPlayer.seekTo(position);
                    mMediaPlayer.start();
                }
            }
        });

        Log.d(TAG, "MediaPlayer is created");
        try {
            mMediaPlayer.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
        Log.d(TAG, "HoverSurface changed");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        Log.d(TAG, "HoverSurface destroyed");
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            //thumbnailImageView.setTag(null);
        }
    }

    public void setAnchorView(View view) {
        mAnchorView = view;
    }

    @Override
    public boolean onHover(View view, MotionEvent motionEvent) {
        try {
            if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
                Log.d(TAG, "ACTION_HOVER_ENTER");

                mSurfaceView = (SurfaceView) findViewById(R.id.media_browser_hoverSurfaceView);

                mHolder = mSurfaceView.getHolder();
                if (mHolder != null) {
                    mHolder.addCallback(this);
                }

            } else if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
                Log.d(TAG, "ACTION_HOVER_EXIT");
                if (mAnchorView.getTag() != null) {
                    MediaPlayer mMediaPlayer = (MediaPlayer) mAnchorView.getTag();
                    mMediaPlayer.stop();
                    mMediaPlayer.release();
                    mAnchorView.setTag(null);
                }
            }
        } catch (Exception e) {
            Log.e(TAG, e.getMessage() + Utils.toString(e.getStackTrace()));
        }
        return false;
    }
}

显示预览的代码:

final PopupWindow popupWindow = new PopupWindow(context);
final HoverPreview hoverPreview = new HoverPreview(context, videoPath, 0);
hoverPreview.setAnchorView(thumbnailImageView);
thumbnailImageView.setOnHoverListener(new View.OnHoverListener() {
    @Override
    public boolean onHover(View view, MotionEvent motionEvent) {
        hoverPreview.onHover(view, motionEvent);
        if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
            popupWindow.setContentView(hoverPreview);
            popupWindow.setWidth(600);
            popupWindow.setHeight(400);
            popupWindow.showAtLocation(thumbnailImageView, ToolHoverPopup.Gravity.NO_GRAVITY, 10, 10);
            Log.d(TAG, "Manual Hover Enter");
        } else if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
            Log.d(TAG, "Manual Hover Exit");
            if (popupWindow != null)
                popupWindow.dismiss();
        }
        return true;
});

1 个答案:

答案 0 :(得分:4)

这是我完整的工作解决方案:

我从SPen库中借用了ToolHoverPopup类的一些代码,我也为这个特殊的弹出窗口进行了自定义,以便在实际悬停发生之前不会创建或膨胀任何内容,这样我们就不会消耗资源来启用这样的在列表中预览。

我们需要将预览附加到Window,因此我们必须管理定位的所有基础工作,这通常由PopupWindow完成,所以我完全删除了对PopupWindow的依赖。 HoverPreview现在我的SurfaceView类完全正常工作并管理所有作业,它还能够以毫秒为单位确定悬停检测延迟。

屏幕截图(已创建SurfaceView)

enter image description here

用法:(由于布局包含onHover且资源密集,我手动触发HoverPreview事件,以便仅在执行真实悬停时才执行真实表面创建。此外,我在需要之前不要创建 thumbnailImageView.setOnHoverListener(new View.OnHoverListener() { @Override public boolean onHover(View view, MotionEvent motionEvent) { HoverPreview hoverPreview; if (thumbnailImageView.getTag() == null) { hoverPreview = new HoverPreview(context, getActivity().getWindow(), videoPath, 0); hoverPreview.setHoverDetectTime(1000); thumbnailImageView.setTag(hoverPreview); } else hoverPreview = (HoverPreview) thumbnailImageView.getTag(); hoverPreview.onHover(null, motionEvent); if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) thumbnailImageView.setTag(null); return true; } }); 的任何对象

HoverPreview

public class HoverPreview extends LinearLayout implements View.OnHoverListener, SurfaceHolder.Callback { private static final int MSG_SHOW_POPUP = 1; private static final int MSG_DISMISS_POPUP = 2; private static final int HOVER_DETECT_TIME_MS = 300; private static final int POPUP_TIMEOUT_MS = 60 * 1000; protected int mHoverDetectTimeMS; private static final String TAG = "HoverPreview"; private SurfaceHolder mHolder = null; String videoPath; int position; private boolean IsMediaPlayerReady = false; private MediaPlayer mMediaPlayer; private SurfaceView mSurfaceView; Context context; private HoverPopupHandler mHandler; Window window; public HoverPreview(Context context, Window window, String videoPath, int position) { super(context); this.mHoverDetectTimeMS = HOVER_DETECT_TIME_MS; this.videoPath = videoPath; this.position = position; this.window = window; setupLayout(context); } private void setupLayout(Context context) { this.context = context; LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); rootView = inflater.inflate(R.layout.media_browser_hover, this); mSurfaceView = (SurfaceView) findViewById(R.id.media_browser_hoverSurfaceView); } View rootView; @Override protected void onFinishInflate() { super.onFinishInflate(); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { Log.d(TAG, "HoverSurface created"); final Surface surface = surfaceHolder.getSurface(); if (surface == null) return; if (!surface.isValid()) return; mHolder = surfaceHolder; mMediaPlayer = new MediaPlayer(); try { mMediaPlayer.setDataSource(videoPath); } catch (IOException e) { e.printStackTrace(); return; } mMediaPlayer.setDisplay(mHolder); mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { Log.d(TAG, "MediaPlayer preview is prepared"); IsMediaPlayerReady = true; int videoWidth = mMediaPlayer.getVideoWidth(); int videoHeight = mMediaPlayer.getVideoHeight(); Point size = new Point(); int screenHeight = 0; int screenWidth = 0; Display display = getDisplay(); display.getSize(size); screenWidth = size.x - (350 + 30); // margin + padding screenHeight = size.y; FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mSurfaceView.getLayoutParams(); lp.width = screenWidth; lp.height = (int) (((float) videoHeight / (float) videoWidth) * (float) screenWidth); mSurfaceView.setLayoutParams(lp); if (mMediaPlayer != null && IsMediaPlayerReady) { if (position > 0) mMediaPlayer.seekTo(position); mMediaPlayer.start(); findViewById(R.id.media_browser_hoverRootFrameLayout).setVisibility(VISIBLE); } } }); Log.d(TAG, "MediaPlayer is created"); try { mMediaPlayer.prepare(); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) { Log.d(TAG, "HoverSurface changed"); } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { Log.d(TAG, "HoverSurface destroyed"); try { if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.release(); } } catch (Exception e) { } } @Override public boolean onHover(View view, MotionEvent motionEvent) { try { if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) { Log.d(TAG, "ACTION_HOVER_ENTER"); show(); // checks the timing } else if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) { Log.d(TAG, "ACTION_HOVER_EXIT"); dismiss(); } } catch (Exception e) { Log.e(TAG, e.getMessage() + Utils.toString(e.getStackTrace())); } return false; } /** * Sets the time that detecting hovering. * * @param ms The time, milliseconds */ public void setHoverDetectTime(int ms) { mHoverDetectTimeMS = ms; } public void dismiss() { dismissPopup(); } private void dismissPopup() { // remove pending message and dismiss popup getMyHandler().removeMessages(MSG_SHOW_POPUP); getMyHandler().removeMessages(MSG_DISMISS_POPUP); try { if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.release(); } } catch (Exception e) { } if (getParent() != null) ((ViewGroup) getParent()).removeView(this); } private Handler getMyHandler() { if (mHandler == null) mHandler = new HoverPopupHandler(); return mHandler; } public void show() { // send message to show. if (getMyHandler().hasMessages(MSG_SHOW_POPUP)) { return; // getHandler().removeMessages(MSG_SHOW_POPUP); } getMyHandler().sendEmptyMessageDelayed(MSG_SHOW_POPUP, mHoverDetectTimeMS); } private void showPopup() { if (getParent() == null) { final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.CENTER_VERTICAL; params.x = 350; window.addContentView(this, params); } mHolder = mSurfaceView.getHolder(); if (mHolder != null) { mHolder.addCallback(this); } } ; private class HoverPopupHandler extends Handler { @Override public void handleMessage(Message msg) { // if (DEBUG) // android.util.Log.e(TAG, "handleMessage : " + ((msg.what == MSG_SHOW_POPUP) ? "SHOW" : "DISMISS")); switch (msg.what) { case MSG_SHOW_POPUP: showPopup(); sendEmptyMessageDelayed(MSG_DISMISS_POPUP, POPUP_TIMEOUT_MS); break; case MSG_DISMISS_POPUP: dismissPopup(); break; } } } }

{{1}}