In my small demo app, I'm showing the camera preview on a SurfaceView. Works fine. But now I want to use a compound XML for the inner preview, so that I can render for example some text onto the camera picture. The layout on screen is:
class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
CameraPreview(Context context) {
super(context);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
}
The preview is created in the main activity:
public class CameraActivity extends Activity {
private CameraPreview mPreview;
Camera mCamera;
int numberOfCameras;
int cameraCurrentlyLocked;
int defaultCameraId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
The simple XML for the main activity:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/camera_preview"
tools:context=".CameraActivity" >
</FrameLayout>
So far so good. But now I added a camera_preview.xml which also includes the SurfaceView that was created in code before.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<SurfaceView
android:id="#+id/renderingView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="blabla" />
</FrameLayout>
When I then change to constructor of the class CameraPreview ...
CameraPreview(Context context) {
super(context);
String inflaterService = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater li;
li = (LayoutInflater) context.getSystemService(inflaterService);
li.inflate(R.layout.camera_preview, this, true);
mSurfaceView = (SurfaceView) findViewById(R.id.renderingView);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
The problem is, that the resulting screen is just white and I don't see the preview neither the text. But I cannot figure out what I'm doing wrong.
Any help appreciated.
Related
I'm new on Android, and i trying to build a camera app.
I build an Camera Preview which extends SurfaceView and implements SurfaceHolder.Callback for previewing the camera on the Camera Activity.
here is the contractor :
public CameraPreview(Context context) {
super(context);
mContext = context;
mStartRequested = false;
mSurfaceAvailable = false;
mCamera = null;
mHolder = getHolder();
mHolder.addCallback(this);
}
and the onCreate(in CameraActivity.java) method which initialize the layout:
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_camera);
mPreview = new CameraPreview(this);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
and finally the Layout XML :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="#+id/button"
android:layout_gravity="center_horizontal|bottom" />
</FrameLayout>
</LinearLayout>
AndroidMainifest.xml:
<application
...
android:theme="#android:style/Theme.Holo.Light.NoActionBar.Fullscreen" >
As you can see i tried to add a button on the camera preview but i cant see the button when the app is lunching.
can anyone see the mistake??
Thanks you !
The preview is probably on top of the button (in the Z-order). This line:
preview.addView(mPreview);
adds the CameraPreview to the end of the FrameLayout's internal list of child views. A FrameLayout renders its child views in order; as such, the preview is being drawn after the button, or "over" it. Try this instead:
preview.addView(mPreview, 0);
You can also order your CameraPreview by having it inflate from the XML instead, by using a tag with the fully qualified class name, like this:
<com.yourdomain.CameraPreview
.../>
...although you will need to override the View(Context context, AttributeSet attrs); constructor to make that work.
I've created a custom view, seen below. I declare this custom view in other xml files. The issue I'm having is that when I call
MyVideoView.setVisibility(View.GONE)
The video that was previously drawn on the SurfaceView is still visible. Shouldn't setting the visibility of the whole View affect the children? Am I missing something?
public class MyVideoView extends FrameLayout {
private SurfaceView videoSurfaceView;
private SurfaceView subtitleSurfaceView;
public MyVideoView(Context context) {
super(context);
initView(context);
}
private void initView(Context context) {
View.inflate(context, R.layout.widget_my_video_view, this);
videoSurfaceView = (SurfaceView) findViewById(R.id.svPlaybackSurface);
subtitleSurfaceView = (SurfaceView) findViewById(R.id.svSubtitles);
}
}
widget_my_video_view.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="#+id/svPlaybackSurface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
<SurfaceView
android:id="#+id/svSubtitles"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginStart="#dimen/paddingRegular"
android:layout_marginEnd="#dimen/paddingRegular"
android:layout_marginBottom="#dimen/paddingLarge"
android:visibility="invisible"/>
</FrameLayout>
actually i'm trying to use camera action(like a 'take a photo') in another activity.
i mean. i got a activity(CameraPreviewActivity). it shows CameraPreview.
if user put the 'draw' button. and then new activity(CanvasActivity) starts. and it show a transparent Canvas.
so user can draw on the Camera preview.
all i want to do is make a 'take a picture' button in the CanvasActivity.
actually its a different activity so i couldn't make a 'take a picture' button in the CavasActivity.
so i use intent.putExtra method to send Camera information. but it's not working at all.
how can i control the CameraPreviewActivity at CanvasActivity.
is my idea wrong ? or is there any good way to figure out this problem.
here's my code.
CameraPreviewActivity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex1);
cameraObject = isCameraAvailiable();
showCamera = new ShowCamera(this, cameraObject);
setCameraDisplayOrientation(this, 0, cameraObject);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(showCamera);
}
public void snapIt(View view) {
cameraObject.takePicture(null, null, capturedIt);
}
public void drawIt(View view) {
Intent intent = new Intent(this, DrawingActivity.class);
startActivity(intent);
}
and it's XML.
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
<Button
android:id="#+id/button_capture"
android:layout_width="136dp"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:onClick="snapIt"
android:text="#string/Capture" />
<Button
android:id="#+id/button_draw"
android:layout_width="126dp"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:onClick="drawIt"
android:text="#string/Draw" />
</FrameLayout>
CanvasActivity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ex2);
findViewById(R.id.myDrawing).setBackgroundColor
(getResources().getColor(android.R.color.transparent));
FrameLayout layout = (FrameLayout) findViewById(R.id.drawingView);
mView = new DrawingView(this);
layout.addView(mView, new LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
init();
}
and it's XML.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/myDrawing"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:color="#00000000" >
<FrameLayout
android:id="#+id/drawingView"
android:layout_width="318dp"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:layout_weight="0.99" >
</FrameLayout>
</LinearLayout>
thanks a lot !!
how can i control the CameraPreviewActivity at CanvasActivity
You don't. Allow the user to take a picture by some means on the CanvasActivity, such as:
via a button, as you originally proposed
via an action bar item
via clicking on the preview itself
via long-clicking on the preview itself
via some other sort of gesture
etc.
I have a class called Panel like this:
public class Test extends Activity{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new Panel(this));
...
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
private LinearLayout layout;
public Panel(Context context) {
super(context);
layout = //get layout resource in layouts folder
}
public void onDraw(Canvas canvas) {
//I want to draw my xml layout
layout.draw(canvas);
}
}
I have tried to use LayoutInflater in order to get my layout:
LayoutInflater inflater = LayoutInflater.from(context);
layout = new LinearLayout(getApplicationContext());
inflater.inflate(R.layout.mylayout, layout);
... but I cant see anything on the screen, only a black background :S
as far as I know you can't draw a linear layout inside the SurfaceView you can draw anything you want in your SurfaceView if you want to add elements to your view like buttons or something like that I recommend using the XML and putting all your elements there. Something like this:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<SurfaceView android:id="#+id/mySurfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</SurfaceView>
<Button android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="myButton"/>
</LinearLayout>
and then you may set your content of your view with setContentView(R.layout.my_xml);
I'm trying to put a camera preview (SurfaceView) together with a button on the display, but all I get is a blank screen only showing the button. If I'm setting the SurfaceView as the only content (with setContentView(surfaceView) then the preview is displaying fine on the screen. What am I doing wrong?
Thanks in advance
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="0px"
android:layout_weight="1">
<SurfaceView
android:id="#+id/camera_surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/trigger"
android:id="#+id/trigger_picture_button"
android:layout_gravity="bottom" />
</FrameLayout>
</LinearLayout>
My Activity:
public class CameraActivity extends Activity {
private SurfaceView cameraPreview;
private Button triggerPicture;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera);
cameraPreview = (SurfaceView) findViewById(R.id.camera_surface);
triggerPicture = (Button) findViewById(R.id.trigger_picture_button);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
cameraPreview = new CameraPreview(this);
// setContentView(cameraPreview);
}
My CameraPreview:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private Camera camera;
public CameraPreview(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
camera = openFrontFacingCamera();
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
camera.release();
camera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(width, height);
parameters.set("orientation", "portrait");
camera.setParameters(parameters);
camera.startPreview();
}
private Camera openFrontFacingCamera() {
// returns Camera.open(
}
When you declare SurfaceView in the layout you tell Android to use built-in class. What you need to do is make it use your class by replacing SurfaceView in XML with your.package.name.CameraPreview.
One other thing: you should add a constructor to the CameraPreview taking parameters Context and AttributeSet, otherwise layout inflater won't be able to inflate your class. Also you don't need the line cameraPreview = new CameraPreview(this);.
When your onCreate() is the right one, than you overriding the cameraPreview from the xml with a new created one which you never add to any layout (last line). That means its never inflated so there is never a surface created.
Maybe it's a bit late answer ,but it really works for me.
1、set the layout as below:
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
/>
<Button
android:id="#+id/button_capture"
android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
2、In onCreate:
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
3、And in Manifest.xml:
android:screenOrientation="landscape"
, of course , don't forget permissions and features.
Hope it helps.