I'm trying to use the SurfaceView widget. I have a class
public class OurView extends SurfaceView implements Runnable {
public OurView(Context context) {
super(context);
Log.d("OurView", "Yay We started");
}
#Override
public void run() {
}
}
So I have a SurfaceView widget in my Activity's XML. I then try to bind it in the onCreate method
TheView = (OurView) findViewById(R.id.theSurfaceView);
The problem is here I get an error that I can't cast OurView to android.view.SurfaceView.
I know usually I could just do this to the view itself, in the onCreateMethod
TheView = new OurView(this);
setContentView(TheView);
The thing is I don't want to do this, I don't want to draw on my whole activity I just want to draw on the SurfaceView widget that i've put on the layout. How would I do that?
You should put your customized SurfaceView com.xx.OurView in your layout, not SurfaceView.
Related
I'm creating a camera app and need to detect Touch on surfaceView which is camera preview. I want to set focus of camera where user touch. But Right i just only need to detect touch place.
Here is my preview class code.
public class Preview extends SurfaceView implements SurfaceHolder.Callback {
public Preview(Context ctx, SurfaceView surfaceView) {
super(ctx);
init(surfaceView);
}
private void init(SurfaceView surfaceView){
mSurfaceView = surfaceView;
final SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
surfaceHolder.addCallback(this);
}
public void setCamera(){
mCamera = Camera.open()
mCamera.setPreviewDisplay(mSurfaceView.getHolder());
mCamera.startPreview();
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i(TAG, "onInterceptTouchEvent");
return true;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.i(TAG, "onTouchEvent");
return super.onTouchEvent(event);
}
// Other code.... like override methods etc
MainActivity
// inside onCreate() method
preview = new Preview(this, surfaceView);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.mainLayout);
mainLayout.addView(preview);
preview.setCamera();
// Other codes .....
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout">
<SurfaceView
android:id="#+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
I added onTouchEvent and onInterceptTouchEvent But both are not working. Whenever I touched on sufaceView nothing show in Log I think I'm missing some thing, can you please let me know ?
preview = new Preview(this, surfaceView);
preview.setCamera();
There is just two line code in MainActivity initilizing the Preview and setCamera() nothing else.
Why you do not see onTouchEvent and onInterceptTouchEvent logs?
I assume, that you haven't added that layout to your view hierarchy.
rootView.addView(preview);
After adding it you should see touch event logs.
But that's not what you actually expect to do, because you have just incorrectly "wrapped" your SurfaceView inside a Java class, which yet doesn't mean that touch events on your SurfaceView would be reflected in your logs.
What you really want is to extend SurfaceView and override those touch events there. Now you would receive correct touch events. Then make sure you are inflating your custom SurfaceView into view hierarchy.
Or, second approach, you can add SurfaceView as a child of your ViewGroup:
yourCustomViewGroup.addView(surfaceView);
There are a few issues with your extended class, in that it does not include all required override methods. However I will assume this is still being developed.
In theory this should work:
preview.setOnClickListener( new OnClickListener(){
#Override
public void onClick() {
//do stuff
}
});
I have not tested it, but as this is extending ViewGroup, this should work.
Note: You probably will need to add this
android:clickable="true"
To your 'Preview' layout, to allow the click to be processed.
Hope that helps.
I'm currently developing an Android App, using a personal SurfaceView and double buffering. However I'm facing a little problem with my code.
In one hand I have an xml view, based on LinearLayout hierarchy. When I instantiate my activity, I set my contentView on this xml. The problem is then that my double buffering don't works anymore. Thread is running but nothing is displayed.
In the other hand, I set my contentView with a new personal SurfaveView element and display works fine. But of course, I cannot access anymore to the other elements of my LinearLayout.
Actually, I would like to set my contentView on my xml view AND keep my display working.
I hope I was clear enough, thank you for your answers!
Here is my activity:
public class MainController extends Activity {
#Override
protected void onCreate(final Bundle p_savedInstanceState) {
super.onCreate(p_savedInstanceState);
setContentView(R.layout.main_controller_activity);
this.drawableView = (MCustomDrawableView) findViewById(R.id.drawingBox);
...
}
...
}
My surface view:
public class MCustomDrawableView extends SurfaceView {
public MCustomDrawableView(Context p_context, AttributeSet p_attributes) {
super(p_context, p_attributes);
this.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(final SurfaceHolder p_holder) {
try {
// Instantiating a new thread
thread = new MBufferingThread(getInstance());
thread.start();
} catch (Exception exception) {
exception.printStackTrace();
}
}
#Override
public void surfaceChanged(final SurfaceHolder p_holder, int p_format, int p_width, int p_height) {...}
#Override
public void surfaceDestroyed(final SurfaceHolder p_holder) {...}
});
// Setup drawing options
setupDrawing();
}
...
}
And my xml view:
<LinearLayout 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:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:background="#color/app_background"
tools:context=".MainController">
<com.iskn.calligraphy.models.draw.MCustomDrawableView
android:id="#+id/drawingBox"
style="#style/DrawingBox" />
<SeekBar
android:id="#+id/brushSize"
style="#style/SizeSeekBar" />
<SeekBar
android:id="#+id/brushOpacity"
style="#style/OpacitySeekBar" />
</LinearLayout>
EDIT:
After further researches and analyses, it appears clearly that:
setContentView(R.layout.main_controller_activity): in this case I get all the elements from my activity, but the MCustomDrawableView display nothing.
setContentView(new MCustomDrawableView(getApplicationContext())): on that case, MCustomDrawableView is working well (it displays what I want), but I don't have the others View from my main_controller_activity
In both cases:
my thread is running and works well.
my drawing function is called as well, with the holder.lockCanvas() and holder.unlockCanvasAndPost(bufferCanvas) methods.
Well, I found a functionnal solution :
I think the problem was coming from the MCustomDrawableView initialization . I created a new instance of that class from the onCreate method , and not from the xml file . Then, I set it to the contentView:
protected void onCreate(Bundle p_savedInstanceState) {
super.onCreate(p_savedInstanceState);
setContentView(R.layout.main_controller_activity);
// Instantiate drawable object & set style properties
this.drawableView = new MCustomDrawableView(getApplicationContext());
FrameLayout.LayoutParams style = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
// Add the drawable view to the main_activity
addContentView(this.drawableView, style);
}
But this way raises a new problem. The added view is on the top, which means that all the others View are hided. I solved this with bringToBack(this.drawableView) below method:
private void bringToBack(View p_view) {
// Get parent from the current view
ViewGroup viewGroup = ((ViewGroup) p_view.getParent());
int childrenCount = viewGroup.indexOfChild(p_view);
for(int cpt = 0; cpt < childrenCount; cpt++) {
// Move the child to the top
viewGroup.bringChildToFront(viewGroup.getChildAt(cpt));
}
}
It brings back the provided view to the background position. I also had to set the LinearLayout's alpha to 0.
I'm still open to other solutions!
What I wanted to achieve is this:
I wanted to have a specific portion of the screen to be my SurfaceView. I will use this SurfaceView for some animations. But I wanted to include some Views like TextView and RadioButtonGroup beside my SurfaceView.
So my question is, is this possible? I looking for sample android source code about 'animating sprites', but I couldn't find any activity that incorporates both TextViews and SurfaceView. All are extending SurfaceView. If this is possible, how do I do it? Do you have sample source codes that I can try?
try this i am not extending surfaceview.
public class Preview_can_work extends Activity {
private SurfaceView surface_view;
SurfaceHolder.Callback sh_ob = null;
SurfaceHolder surface_holder = null;
SurfaceHolder.Callback sh_callback = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
surface_view = new SurfaceView(getApplicationContext());
addContentView(surface_view, new LayoutParams(50, 50));
if (surface_holder == null) {
surface_holder = surface_view.getHolder();
}
sh_callback = my_callback(); // CREATING CALLBACK FOR YOUR SURFACE.
surface_holder.addCallback(sh_callback);
}
// THIS FUNCTION RETURNS CALLBACK OBJECT FOR SURFACEVIEW.
SurfaceHolder.Callback my_callback() {
SurfaceHolder.Callback ob1 = new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
};
return ob1;
}
}
now you can simply add any textview or button on your layout it should work.
Note:- I am creating surface dynamically. In your case what you can do is you can create everything in xml file. Instead of creating surfaceview create video view.
SurfaceView surface_view = (SurfaceView) findViewById(R.id.video_view_id);
if you are fetch view by id from your layout then you have to remove some line from code. which are:
surface_view = new SurfaceView(getApplicationContext());
addContentView(surface_view, new LayoutParams(50, 50));
Hope it will help you...
It is definitely possible but you might need to present a little more information. If you want some simple animation to run next to the textview then you don't even need a surfaceview. Just create an imageview and run an animation on it (here is a tutorial I created for the very topic)
TextView and its kin DO NOT derive from Surfaceview they derive from the View class. Once again if you want to perform simple animations I don't think you will need a surfaceview. If you want to do more dynamic complex things then there is also a tutorial on my development blog on how to utilize a SurfaceView for a game. If that is more your flavor then you can create a custom surface view and then just tie it into your layout with the size dimensions you want.
Layouting in Android is getting me rather perplexed.
I'm slowly implementing a custom ImageView where I'd like to make use of the ZoomButtonsController.
However, I would like to decide where the zoom buttons go in the layout and I can't figure out how to move them from the default bottom center position.
I have been experimenting with layouting simple views such as buttons in the main activity and this seems to be working as I would guess and expect.
In the case of the ZoomButtonsController I would however like to reposition them. I'm using a RelativeLayout as the mail layout and add the ZoomButtonsController within the custom ImageView.
The Activity code
public class ImageViewActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
CustomImageView imageView = new CustomImageView(this);
relativeLayout.addView(imageView);
}
}
The CustomImageView code
public class CustomImageView extends ImageView {
private ZoomButtonsController mZoomButtons;
public CustomImageView(Context context) {
super(context);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
mZoomButtons = new ZoomButtonsController(this);
mZoomButtons.getZoomControls();
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
setLayoutParams(layoutParams);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
Log.d("TAG", "touch");
mZoomButtons.setVisible(true);
return true;
}
}
I've tested with WRAP_CONTENT in the parameters, but this only makes the zoom buttons disappear.
As a matter of fact, I couldn't position the ZoomButtonsController in any way and in the end had to accept the default placement.
I have subclassed the SurfaceView and instantiating it in onCreate of the Activity. The preview is generated but the control never enters onDraw() which is overriden in the subclass of SurfaceView. Why is that?
class ActivityClass extends Activity{
onCreate(){
mPreview = new Preview(this);
setContentView(mPreview);
}
public void startPreview(){
rec = new MediaRecorder();
rec.setVideoSource();.......
rec.setPreviewDisplay(mPreview.getSurfaceHolder.getSurface());
}
}
class Preview extends SurfaceView implements SurfaceHolder.Callback{
SurfaceHolder mHolder;
public Preview(Context context){
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
bringToFront();//this is not
invalidate();//making a difference
}
SurfaceHolder getSurfaceHolder(){
return mHolder;
}
//Surface callback methods implemented here
}
Before drawing the preview on the Surface, shouldn't the control be given to the onDraw callback if it is implemented?
Because onDraw callback says to the Android framework 'you don't draw the view. I will draw it since I have been implemented'. Am I right?
Why then, is the control failing to enter onDraw()? Please help.
You simply have to add
setWillNotDraw(false)
To the constructor.
And its done..:)
public class SelectedRect extends View {
public SelectedRect(Context context) {
super(context);
bringToFront();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawLine(canvas);
invalidate();
this.bringToFront();
}
}
And in activity class :
View rect = new SelectedRect(this);
rect.bringToFront();
this.addView(rect, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
Something fishy is going on. It seems that you're trying to set the SurfaceView as a preview display. In that case, the Activity should implement SurfaceHolder.Callback (not the SurfaceView). This is so that the Activity can know when the SurfaceView has been created and is ready for drawing. Furthermore, it shouldn't even be necessary to extend SurfaceView: you should be able to user SurfaceView itself.
Assuming I misunderstood and you really want to extend surfaceview for some reason...
I don't see where you overrode onDraw in your Preview class. Did you not include this code?
When you say that the onDraw callback tells android 'you don't draw the view. I will draw it since I have been implemented', I disagree. onDraw is a function where a View draws stuff that all views have, such as the background. SurfaceView extends view. When you extend SurfaceView, you can override onDraw to tell android to draw stuff in addition to what the original onDraw in the View draws. In other words, Android always does all the drawing; overriding onDraw just tells it to draw a few more things when it's the right time to draw.