Androidはコントロールシリーズを書きます.豚はあなたにカメラを書くように言いました.
29991 ワード
前記:Androidというオープンソースで自由なシステムは、開発の便利さをもたらし、深い穴を埋めすぎます.例えば、システムが持っているカメラを呼び出すと、写真が紛失したり、いろいろな問題が発生します.そのため、カメラをカスタマイズする必要があるようです.
カメラをカスタマイズするにはsurfaceviewとcamera付きの2つの利器を利用することはできません.
まずsurfaceviewの基本的な意味を理解します.
通常、プログラムのViewとユーザ応答は同じスレッドで処理されます.これは、長時間のイベント(例えば、ネットワークへのアクセス)を処理するには、現在のUIスレッドをブロックする操作や描画を防止するために、別のスレッドに配置する必要がある理由です.ただし、他のスレッドではUI要素を変更することはできません.たとえば、バックグラウンドスレッドでカスタムView(カスタムViewのonDraw関数を呼び出す)を更新することはできません.インタフェースを別のスレッドで描画する必要がある場合、インタフェースを迅速に更新する必要がある場合、またはUIインタフェースをレンダリングするのに時間がかかる場合は、Surface Viewを使用します.
Surface ViewにはSurfaceオブジェクトが含まれていますが、Surfaceはバックグラウンドスレッドで描画できます.SurfaceはOPhoneの下部表示システムに属しています.Surface Viewの性質は、インタフェースの迅速な更新が必要で、フレームレートに対する要求が高い場合に、いくつかのシーンに適していることを決定します.Surface Viewを使用するには、以下の点に注意する必要がある:Surface ViewとSurface Holder.Callback関数は、現在のSurface Viewウィンドウスレッドから呼び出されます(一般的にはプログラムのプライマリスレッド).リソースステータスについては、ペイントスレッドとの同期に注意してください.SurfaceHolderでは、描画スレッドでSurfaceを合法的に取得する必要があります.Callback.surfaceCreated()とSurfaceHolder.Callback.surfaceDestroyed()間の状態は正当であり、またSurfaceタイプではSURFACE_TYPE_PUSH_BUFFERSの場合は合法ではありません.追加の描画スレッドはシステムのリソースを消費するので、Surface Viewを使用するときは注意してください.
こんなにたくさん知ったので、カメラを書き始めました.まず,リフレッシュインタフェースを判断するためにsurfaceviewが必要である.同様にsurefaceviewの3要素holder,callback,created.
SurfaceViewを使用するには、SurfaceViewクラスを継承し(1)SurfaceHolderを実現する.Callbackインタフェースは、(2)SurfaceHolderをカスタマイズすることができます.Callbackは、下位層のSurface状態が変化したときにView,Surface Holderに通知する.Callbackには、次のインタフェースがあります.
(3)surfaceCreated(SurfaceHolder holder):Surfaceが初めて作成されるとすぐに呼び出されます.プログラムはこの関数で描画インタフェースに関する初期化作業を行うことができ、一般的には別のスレッドでインタフェースを描画するので、この関数でSurfaceを描画しないでください.
これらの理論の敷居があれば、surfaceCreatedでcameraを開いてフォーカスさせ、写真を撮る操作を行う必要があります.対応するソースコードは以下の通りです.
コードを通じて、cameraオブジェクトを利用していることが明らかになりました.彼は何ですか.彼はAndroidが提供するカメラ操作に対応するAPIです.上記のコードを見て、camera撮影の範囲を1024以下に制御し、プレビューの実際のsurefaceviewの範囲内に設定します.
これで簡単にカメラが作れるはずです.しかし、そんなに完璧ではないようです.私たちのカメラはどんなものが悪いようですか.まず、手動フォーカス絞りが必要です.この機能を完了するには、作業量が少なくありません.まずfocusmanagerがフォーカスの操作を管理する必要があります.彼の内部には次のようなものがあります.
まず、そのcameraオブジェクトのフォーカスを操作するように通知するcameraオブジェクトがあります.
このオブジェクトを上から下へスキャンし、最も多くの操作がフォーカス調整であることを観察します.checkFocusでは、一定時間の範囲内で強制的にフォーカスさせる.refocusという方法では、ユーザのオートフォーカスが開始され、フォーカス絞りの変化を調整するために、対応するフォーカス状態の変化をリスニングする.一方、isFocusAreaSupportedメソッドでは、cameraオブジェクトがサポートするパラメータのフォーカスの最大範囲が0より大きいかどうかを判断します.この一連の判断論理を経て,cameraフォーカスを制御した.
私たちが次にしなければならないのは、焦点を合わせた絞りに小言を言う必要があることです.フォーカス絞りはカメラのフォーカス領域で絞りを表示します.彼のクラス名はFocusHudRingです.ソースコードは次のとおりです.
focushudringは単純に存在するわけではありませんが、hudringというカスタムコントロールを継承し、ユーザーがある領域をクリックすると、このコントロールは一定の領域に現れます.このsetpositionコントロールによって、applyfocuspointはこの円形を計算し、アニメーションを開きます.
この2つのクラスがあれば、カスタムフォーカスコントロールができます.あなたがしているのは画面のジェスチャーイベントを監視することです.私の言うことがはっきりしていないかもしれませんが、コードを見てください.コードの場所は次のとおりです.
カメラをカスタマイズするにはsurfaceviewとcamera付きの2つの利器を利用することはできません.
まずsurfaceviewの基本的な意味を理解します.
通常、プログラムのViewとユーザ応答は同じスレッドで処理されます.これは、長時間のイベント(例えば、ネットワークへのアクセス)を処理するには、現在のUIスレッドをブロックする操作や描画を防止するために、別のスレッドに配置する必要がある理由です.ただし、他のスレッドではUI要素を変更することはできません.たとえば、バックグラウンドスレッドでカスタムView(カスタムViewのonDraw関数を呼び出す)を更新することはできません.インタフェースを別のスレッドで描画する必要がある場合、インタフェースを迅速に更新する必要がある場合、またはUIインタフェースをレンダリングするのに時間がかかる場合は、Surface Viewを使用します.
Surface ViewにはSurfaceオブジェクトが含まれていますが、Surfaceはバックグラウンドスレッドで描画できます.SurfaceはOPhoneの下部表示システムに属しています.Surface Viewの性質は、インタフェースの迅速な更新が必要で、フレームレートに対する要求が高い場合に、いくつかのシーンに適していることを決定します.Surface Viewを使用するには、以下の点に注意する必要がある:Surface ViewとSurface Holder.Callback関数は、現在のSurface Viewウィンドウスレッドから呼び出されます(一般的にはプログラムのプライマリスレッド).リソースステータスについては、ペイントスレッドとの同期に注意してください.SurfaceHolderでは、描画スレッドでSurfaceを合法的に取得する必要があります.Callback.surfaceCreated()とSurfaceHolder.Callback.surfaceDestroyed()間の状態は正当であり、またSurfaceタイプではSURFACE_TYPE_PUSH_BUFFERSの場合は合法ではありません.追加の描画スレッドはシステムのリソースを消費するので、Surface Viewを使用するときは注意してください.
こんなにたくさん知ったので、カメラを書き始めました.まず,リフレッシュインタフェースを判断するためにsurfaceviewが必要である.同様にsurefaceviewの3要素holder,callback,created.
SurfaceViewを使用するには、SurfaceViewクラスを継承し(1)SurfaceHolderを実現する.Callbackインタフェースは、(2)SurfaceHolderをカスタマイズすることができます.Callbackは、下位層のSurface状態が変化したときにView,Surface Holderに通知する.Callbackには、次のインタフェースがあります.
(3)surfaceCreated(SurfaceHolder holder):Surfaceが初めて作成されるとすぐに呼び出されます.プログラムはこの関数で描画インタフェースに関する初期化作業を行うことができ、一般的には別のスレッドでインタフェースを描画するので、この関数でSurfaceを描画しないでください.
これらの理論の敷居があれば、surfaceCreatedでcameraを開いてフォーカスさせ、写真を撮る操作を行う必要があります.対応するソースコードは以下の通りです.
private void initSurfaceView() {
try {
camera = Camera.open();// , android.hardware.Camera
Camera.Parameters parameters = camera.getParameters();//
int PreviewWidth = 0;
int PreviewHeight = 0;
List<Camera.Size> size_list = parameters.getSupportedPreviewSizes();
if (size_list.size() > 0) {
Iterator<Camera.Size> itor = size_list.iterator();
while (itor.hasNext()) {
Camera.Size cur = itor.next();
if (cur.width >= PreviewWidth
&& cur.height >= PreviewHeight) {
PreviewWidth = cur.width;
PreviewHeight = cur.height;
// break;
}
}
}
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);//
// Display display = wm.getDefaultDisplay();//
parameters.setPreviewSize(PreviewWidth, PreviewHeight);//
parameters.setPictureFormat(PixelFormat.JPEG);//
parameters.setJpegQuality(100);//
System.out.println(camera.getParameters().flatten());
List<Size> picSizeValues = camera.getParameters()
.getSupportedPictureSizes();
if (picSizeValues.get(0).width > picSizeValues.get(picSizeValues
.size() - 1).width) {
for (Size size : picSizeValues) {
Log.v("show", size.width + "
");
if (size.width <= 1024) {
parameters.setPictureSize(size.width, size.height);// ,
break;
}
}
} else {
for (int i = picSizeValues.size() - 1; i >= 0; i -= 1) {
Log.v("show", picSizeValues.get(i).width + "
");
if (picSizeValues.get(i).width <= 1024) {
parameters.setPictureSize(picSizeValues.get(i).width,
picSizeValues.get(i).height);
break;
}
}
}
parameters.setFlashMode(parameters.FLASH_MODE_AUTO);
//
camera.setParameters(parameters);
camera.setPreviewDisplay(surface_view.getHolder());// SurfaceView
camera.startPreview();//
is_preview = true;//
} catch (IOException e) {
// Log.e(TAG, e.toString());
}
}
コードを通じて、cameraオブジェクトを利用していることが明らかになりました.彼は何ですか.彼はAndroidが提供するカメラ操作に対応するAPIです.上記のコードを見て、camera撮影の範囲を1024以下に制御し、プレビューの実際のsurefaceviewの範囲内に設定します.
これで簡単にカメラが作れるはずです.しかし、そんなに完璧ではないようです.私たちのカメラはどんなものが悪いようですか.まず、手動フォーカス絞りが必要です.この機能を完了するには、作業量が少なくありません.まずfocusmanagerがフォーカスの操作を管理する必要があります.彼の内部には次のようなものがあります.
private Camera mCamera;
private static final String TAG="FocusManager";
private static final int FOCUS_WIDTH = 80;
private static final int FOCUS_HEIGHT = 80;
public interface FocusListener {
public void onFocusStart(boolean smallAdjust);
public void onFocusReturns(boolean smallAdjust, boolean success);
}
private int mFocusKeepTimeMs = 3000;
private long mLastFocusTimestamp = 0;
private Handler mHandler;
private FocusListener mListener;
private boolean mIsFocusing;
public final FocusManager mfocusManager;
private Object mParametersSync=new Object();
public FocusManager(Camera mCamera) {
mHandler = new Handler();
mIsFocusing = false;
this.mCamera = mCamera;
mfocusManager=this;
Camera.Parameters params = mCamera.getParameters();
if (params.getSupportedFocusModes().contains("auto")) {
params.setFocusMode("auto");
}
// Do a first focus after 1 second
mHandler.postDelayed(new Runnable() {
public void run() {
checkFocus();
}
}, 1000);
}
public void setListener(FocusListener listener) {
mListener = listener;
}
public void checkFocus() {
long time = System.currentTimeMillis();
if (time - mLastFocusTimestamp > mFocusKeepTimeMs && !mIsFocusing) {
refocus();
} else if (time - mLastFocusTimestamp > mFocusKeepTimeMs * 2) {
// Force a refocus after 2 times focus failed
refocus();
}
}
public void refocus() {
if (doAutofocus(this)) {
mIsFocusing = true;
if (mListener != null) {
mListener.onFocusStart(false);
}
}
}
private boolean doAutofocus(FocusManager focusManager) {
if (mCamera != null) {
try {
// Trigger af
mCamera.cancelAutoFocus();
mHandler.post(new Runnable() {
public void run() {
try {
mCamera.autoFocus(mfocusManager);
} catch (Exception e) {
// Do nothing here
}
}
});
} catch (Exception e) {
return false;
}
return true;
} else {
return false;
}
}
@Override
public void onAutoFocus(boolean success, Camera camera) {
mLastFocusTimestamp = System.currentTimeMillis();
mIsFocusing = false;
if (mListener != null) {
mListener.onFocusReturns(false, success);
}
}
/***
*
* @return
*/
@SuppressLint("NewApi")
public boolean isFocusAreaSupported() {
if (mCamera != null) {
try {
return (getParameters().getMaxNumFocusAreas() > 0);
} catch (Exception e) {
return false;
}
} else {
return false;
}
}
private Parameters getParameters() {
Parameters Parameters=null;
synchronized (mParametersSync) {
if (mCamera == null) {
Log.w("", "getParameters when camera is null");
return null;
}
int tries = 0;
while (Parameters == null) {
try {
Parameters = mCamera.getParameters();
break;
} catch (RuntimeException e) {
Log.e(TAG, "Error while getting parameters: ", e);
if (tries < 3) {
tries++;
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
} else {
Log.e(TAG, "Failed to get parameters after 3 tries");
break;
}
}
}
}
return Parameters;
}
@SuppressLint("NewApi")
public void setFocusPoint(int x, int y) {
if (x < -1000 || x > 1000 || y < -1000 || y > 1000) {
Log.e(TAG, "setFocusPoint: values are not ideal " + "x= " + x + " y= " + y);
return;
}
Camera.Parameters params = getParameters();
if (params != null && params.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusArea = new ArrayList<Camera.Area>();
focusArea.add(new Camera.Area(new Rect(x, y, x + FOCUS_WIDTH, y + FOCUS_HEIGHT), 1000));
params.setFocusAreas(focusArea);
try {
mCamera.setParameters(params);
} catch (Exception e) {
}
}
}
まず、そのcameraオブジェクトのフォーカスを操作するように通知するcameraオブジェクトがあります.
このオブジェクトを上から下へスキャンし、最も多くの操作がフォーカス調整であることを観察します.checkFocusでは、一定時間の範囲内で強制的にフォーカスさせる.refocusという方法では、ユーザのオートフォーカスが開始され、フォーカス絞りの変化を調整するために、対応するフォーカス状態の変化をリスニングする.一方、isFocusAreaSupportedメソッドでは、cameraオブジェクトがサポートするパラメータのフォーカスの最大範囲が0より大きいかどうかを判断します.この一連の判断論理を経て,cameraフォーカスを制御した.
私たちが次にしなければならないのは、焦点を合わせた絞りに小言を言う必要があることです.フォーカス絞りはカメラのフォーカス領域で絞りを表示します.彼のクラス名はFocusHudRingです.ソースコードは次のとおりです.
private FocusManager mFocusManager;
public FocusHudRing(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public FocusHudRing(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public FocusHudRing(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
@SuppressLint("ClickableViewAccessibility")
protected void onFinishInflate() {
// TODO Auto-generated method stub
super.onFinishInflate();
setImage(true);
}
public void setImage(boolean success) {
// TODO Auto-generated method stub
if (success) {
setImageResource(R.drawable.hud_focus_ring_success);
} else {
setImageResource(R.drawable.hud_focus_ring_fail);
}
}
public void setPosition(float x, float y) {
setX(x - getWidth() / 2.0f);
setY(y - getHeight() / 2.0f);
applyFocusPoint();
}
private void applyFocusPoint() {
ViewGroup parent = (ViewGroup) getParent();
if (parent == null) return;
// We swap X/Y as we have a landscape preview in portrait mode
float centerPointX = getY() + getHeight() / 2.0f;
float centerPointY = parent.getWidth() - (getX() + getWidth() / 2.0f);
centerPointX *= 1000.0f / parent.getHeight();
centerPointY *= 1000.0f / parent.getWidth();
centerPointX = (centerPointX - 500.0f) * 2.0f;
centerPointY = (centerPointY - 500.0f) * 2.0f;
if (mFocusManager != null) {
mFocusManager.setFocusPoint((int) centerPointX, (int) centerPointY);
}
}
public boolean onTouch(View view, MotionEvent motionEvent) {
super.onTouch(view, motionEvent);
if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
applyFocusPoint();
if (mFocusManager != null) {
mFocusManager.refocus();
}
}
return true;
}
public FocusManager getFocusManager() {
return mFocusManager;
}
public void setFocusManager(FocusManager mFocusManager) {
this.mFocusManager = mFocusManager;
}
focushudringは単純に存在するわけではありませんが、hudringというカスタムコントロールを継承し、ユーザーがある領域をクリックすると、このコントロールは一定の領域に現れます.このsetpositionコントロールによって、applyfocuspointはこの円形を計算し、アニメーションを開きます.
この2つのクラスがあれば、カスタムフォーカスコントロールができます.あなたがしているのは画面のジェスチャーイベントを監視することです.私の言うことがはっきりしていないかもしれませんが、コードを見てください.コードの場所は次のとおりです.