Android Camera学习(一):如何实现转动屏幕界面菜单跟着转动效果

最近公司在做车载项目,需要把照相机原本竖向显示改为横向显示。所以研究了下camera菜单朝向的问题。

系统提供了一个监听sensor状态变化的类OrientationEventListener。在系统代码CameraActivity中就是继承的这个类。

 private class MyOrientationEventListener
            extends OrientationEventListener {
        public MyOrientationEventListener(Context context) {
            super(context);
        }

        @Override
        public void onOrientationChanged(int orientation) {
            // We keep the last known orientation. So if the user first orient
            // the camera then point the camera to floor or sky, we still have
            // the correct orientation.
            if (orientation == ORIENTATION_UNKNOWN) {
                return;
            }
            if (mOrientationCorrectedValue != -1)
                orientation = mOrientationCorrectedValue + orientation;
            mLastRawOrientation = orientation;
            mCurrentModule.onOrientationChanged(orientation);
            OnScreenHint.globalOrientaion = orientation;
            if (mStorageHint != null)
            {
                mStorageHint.onOrientationChanged();
            }
        }
    }
这个类在onCrate方法中构造对象mOrientationListener = new MyOrientationEventListener(this);,在onResume方法中开始监听 mOrientationListener.enable();,在onPause()方法中取消监听mOrientationListener.disable();

接下来,我们仔细分析下onOrientationChanged(int orientation)代码:当我们转动手机时,sensor值就会发生变化就会调用这个方法。

mOrientationCorrectedValue这个值在oncreta方法中继续了赋值 mOrientationCorrectedValue = CameraUtil.getInitOrientation(); 

   public static int getInitOrientation() {
        return mInitOrientation;
    }

    public static void updateInitOrientation() {
        IBinder displayToken = SurfaceControl.getBuiltInDisplay(0);
        if (displayToken != null && SurfaceControl.getDisplayInfo(displayToken, mTempPhys)) {
            Log.d(TAG, "displayinfo width:" + mTempPhys.width + " height:" + mTempPhys.height);
            mInitOrientation =  mTempPhys.width > mTempPhys.height ? 270 : 0;
        }
    }
这里就是判断你手机是横屏手机还是竖屏手机的地方。

mCurrentModule.onOrientationChanged(orientation); 这句代码才是这个监听的核心。

 private CameraModule mCurrentModule; CameraModule类是一个接口类,这个地方是由 PhotoModule  implements CameraModule实现的。

    public void onOrientationChanged(int orientation) {
        // We keep the last known orientation. So if the user first orient
        // the camera then point the camera to floor or sky, we still have
        // the correct orientation.
        if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
        mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
        // Show the toast after getting the first orientation changed.
        if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) {
            mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST);
            showTapToFocusToast();
        }
        mUI.onOrientationChanged(mOrientation);
        if (mParameters != null && (mOldOrientation != mOrientation) && mCameraId != -1
                && mCameraDevice != null && mOrientation % 90 == 0) {
            mParameters.setRotation(mMirror ? (720 - (mOrientation + mDisplayOrientation)) % 360
                    : (mOrientation + mDisplayOrientation) % 360);
            mCameraDevice.setParameters(mParameters);
            Log.i(TAG, "onOrientationChanged()  mOrientation=" + mOrientation
                    + "mDisplayOrientation=" + CameraUtil.getCameraOrientation(mCameraId) + mMirror);
        }
        if (mAllowRotateMemoryUseToast && mRotateMemoryUseToast != null) {
            mRotateMemoryUseToast.onOrientationChanged(mOrientation);
        }
        mOldOrientation = mOrientation;
    }

mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);这句就是由sensor给的值取方向的核心代码。

  public static int roundOrientation(int orientation, int orientationHistory) {
        boolean changeOrientation = false;
        if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
            changeOrientation = true;
        } else {
            int dist = Math.abs(orientation - orientationHistory);
            dist = Math.min( dist, 360 - dist );
            changeOrientation = ( dist >= 45 + ORIENTATION_HYSTERESIS );
        }
        if (changeOrientation) {
            return ((orientation + 45) / 90 * 90) % 360;
        }
        return orientationHistory;
    }
 mUI.onOrientationChanged(mOrientation);而这句就是更具朝向来显示UI效果。  private PhotoUI mUI;
 public void onOrientationChanged(int orientation) {
        // Log.d(TAG, "orientation = "+orientation);
        if (orientation == OrientationListener.ORIENTATION_UNKNOWN)
            return;
        orientation = orientation % 360;
        mOrientation = orientation;
        if (mModuleView != null) {
            mModuleView.setOrientation(orientation, true);
        }
        if (mCameraEffectView != null) {
            mCameraEffectView.setOrientation(orientation, false);
        }

        if (mPreviewThumb != null) {
            mPreviewThumb.setOrientation(orientation, true);
        }

        if ((mSwitcher != null) && (mSwitcherBg != null)) {
            mSwitcher.setOrientation(orientation, true);
            mSwitcherBg.setOrientation(orientation, true);
        }

        if (mShutterButton != null) {
            mShutterButton.setOrientation(orientation, true);
        }

        if (mSwitchCameraVideoLayout != null) {
            mSwitchCameraVideoLayout.setOrientation(orientation, true);
        }

        if (Settings.System.getInt(mActivity.getContentResolver(),
                Settings.System.ACCELEROMETER_ROTATION, 0) == 1) {
            if (mCameraIntentShowLayout != null) {
                mCameraIntentShowLayout.setOrientation(orientation, false);
            }
        }

        if (mBurstToastLayout != null) {
            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mBurstModeLayout
                    .getLayoutParams();
            lp.setMargins(0, 0, 0, CameraUtil.dpToPixel((orientation % 180==0)? 60:30));
            mBurstModeLayout.setLayoutParams(lp);
            mBurstToastLayout.setOrientation(orientation, false);
        }
        showModuleText();

        if (mPopup != null) {
            mPopup.setOrientation(orientation, false);
        }
        if (mPopupBottomMenu != null) {
            if (mPopupBottomMenu.isShowing()) {
                mPopupBottomMenu.setOrientation(orientation, false);
                mPopupBottomMenu.showAccordOrientation();
            }
            mPopupBottomMenu.setOrientation(orientation, false);
        }

        if (mDMenuUi != null) {
            mDMenuUi.onOrientationChanged(orientation);
        }
        if (mZoomRenderer != null) {
            mZoomRenderer.setOrientation(orientation, false);
        }
    }
这段代码可以看出camera将整体界面封装成一个个单独的view,有view来显示不同的ui效果,这里mModuleView为例分析    private ModuleSwitchView mModuleView;

public void setOrientation(int orientation, boolean animation) {
        // TODO Auto-generated method stub
        if (mOrientation == orientation) return;
        mOrientation = orientation;
        if (mModuleToastLayout != null && mModuleToastLinearLayout != null) {
            mModuleToastLayout.setOrientation(orientation, false);
            switch (orientation) {
            case 0:
                mModuleToastLinearLayout
                        .setBackgroundResource(R.drawable.description_bubble_popup_01);
                break;
            case 90:
                mModuleToastLinearLayout
                        .setBackgroundResource(R.drawable.description_bubble_popup_04);
                break;
            case 180:
                mModuleToastLinearLayout
                        .setBackgroundResource(R.drawable.description_bubble_popup_02);
                break;
            case 270:
                mModuleToastLinearLayout
                        .setBackgroundResource(R.drawable.description_bubble_popup_03);
                break;
            }
        }
        if (mButtonGrid != null) {
            mButtonGrid.setOrientation(orientation, true);
        }
        if (mButtonAuto != null) {
            mButtonAuto.setOrientation(orientation, true);
        }
        if (mRotateGridModule != null) {
            LayoutParams lp = (FrameLayout.LayoutParams) mGridViewModule.getLayoutParams();
            if (orientation % 180 == 0) {
                lp.setMargins(0, CameraUtil.dpToPixel(60), 0, CameraUtil.dpToPixel(60));
            } else {
                lp.setMargins(CameraUtil.dpToPixel(60), 0, CameraUtil.dpToPixel(60), 0);
            }
            mGridViewModule.setLayoutParams(lp);
            mGridViewModule.setOrientation(orientation, false);
            mRotateGridModule.setOrientation(orientation, false);
        }
        if (mGalleryModule != null) {
            mGalleryModule.setOrientation(orientation, false);
        }
    }
可以看出根据不同的orientation值,来获取对应的ui界面。有兴趣的小伙伴可以分析分析别的view代码,可以学到很多新知识。

同样的video界面的朝向,也是和camera界面差不多的。










  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值