I'm struggling to find any tutorial to help me put a SurfaceView in a box. A pointer in the right direction would be amazing - not looking for a hand hold through it.
I'd like to be able to apportion an area at the top of the screen for example to do buttons etc and then have a surfaceview filling the rest. However, when I try to modify the code I've used for full screen surfaceView to reference my xml, it all goes a bit wrong.
My code for my main activity is as follows (I've stripped out a lot of the bits I think aren't relevant).
package com.example.mylistviewidea;
import android.os.Bundle;
etc...
public class MainActivity extends Activity implements OnTouchListener {
MyListView myListView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myListView = (MyListView) findViewById(R.id.surfaceView1);
}
class MyListView extends SurfaceView implements Runnable {
SurfaceHolder myHolder;
Thread myThread = null;
boolean isRunning = false;
// My Variables
long dT;
int myRed;
public MyListView(Context context) {
super(context);
myHolder = getHolder();
}
#Override
public void run() {
// TODO Auto-generated method stub
while (isRunning) {
if (!myHolder.getSurface().isValid())
continue;
Canvas canvas = myHolder.lockCanvas();
canvas.drawARGB(128, 0, 0, 0);
dT = SystemClock.uptimeMillis();
myRed = (int) ((int) 128*(1+Math.sin((double) dT/1000)));
}
}
}
}
My XML is:
<RelativeLayout 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"
tools:context=".MainActivity" >
<SurfaceView
android:id="#+id/surfaceView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="#string/add_entries" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/button1"
android:text="#string/remove_entries" />
</RelativeLayout>
The error I'm getting is:
02-08 11:44:17.885: E/AndroidRuntime(10523): java.lang.RuntimeException: Unable
to start activity ComponentInfo{com.example.mylistviewidea/com.example.mylistviewidea.MainActivity}:
java.lang.ClassCastException: android.view.SurfaceView cannot be cast to
com.example.mylistviewidea.MyListView
Thanks in advance for your help!
Cheers,
Mike
You should have a custom view and use it in your xml.
First create this view
class MyListView extends SurfaceView implements Runnable {
SurfaceHolder myHolder;
Thread myThread = null;
boolean isRunning = true;
// My Variables
long dT;
int myRed;
public MyListView(Context context) {
super(context);
init();
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
myHolder = getHolder();
myHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void run() {
// TODO Auto-generated method stub
while (isRunning) {
if (!myHolder.getSurface().isValid())
continue;
Canvas canvas = myHolder.lockCanvas();
canvas.drawARGB(128, 128, 0, 0);
dT = SystemClock.uptimeMillis();
myRed = (int) ((int) 128 * (1 + Math.sin((double) dT / 1000)));
myHolder.unlockCanvasAndPost(canvas);
}
}
}
Change your xml to this
<RelativeLayout 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"
tools:context=".MainActivity" >
<com.example.testant.MyListView
android:id="#+id/surfaceView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="add_entries" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/button1"
android:text="remove_entries" />
and change main activity
public class MainActivity extends Activity {
MyListView myListView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myListView = (MyListView) findViewById(R.id.surfaceView1);
new Thread(myListView).start();
}
}
Note that you also have a bug with lock canvas, but this should work fine.
It might be a bit trivial. But try to clean project and then do a rebuild.
OR
Declare a MyListView in a separate java class file and the reference it in your xml layout file,
Related
When I declare and try to get a reference to my button, which I declare in XML, the app won't open and I don't know why. PLEASE try to explain to me why not -- don't just give a link.
Here's the code:
public class MainActivity extends AppCompatActivity {
final String stream="<iframe width=\"300\" height=\"193\" src=\"http://cdn.livestream.com/embed/sl48?layout=4&color=0xffad4b&autoPlay=true&mute=false&iconColorOver=0xe17b00&iconColor=0xb96500&allowchat=true&height=193&width=300\" style=\"border:0;outline:0\" frameborder=\"0\" scrolling=\"no\"></iframe>";
// Button button = (Button) findViewById(R.id.home);
//final Button button1 = (Button) findViewById(R.id.stream);
//final Button button2 = (Button) findViewById(R.id.contatti);
WebView custumWebView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
custumWebView = (WebView) findViewById(R.id.webView);
custumWebView.loadData(stream, "text/html", null);
custumWebView.getSettings().setJavaScriptEnabled(true);
custumWebView.getSettings().setLoadsImagesAutomatically(true);
custumWebView.clearHistory();
custumWebView.clearCache(true);
custumWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
}
public class CustomWebView extends WebView {
public CustomWebView (Context context) {
super( context );
init();
}
public CustomWebView (Context context, AttributeSet attrs) {
super( context, attrs );
init();
}
public CustomWebView (Context context, AttributeSet attrs, int defStyle) {
super( context, attrs, defStyle );
init();
}
public CustomWebView (Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
super( context, attrs, defStyle, privateBrowsing );
init();
}
protected void init () {
getSettings().setJavaScriptEnabled( true );
setWebViewClient( new CustomWebViewClient() );
setDownloadListener( new CustomDownloadListener() );
}
protected boolean overrideUrlLoading (WebView view, String url) {
// ANY CUSTOM LOGIC GOES HERE
view.loadUrl(url);
return true;
}
protected void pageFinished (WebView view, String url) {
}
protected void downloadStarted(String url, String mimetype) {
try {
//Start new activity to load the specific url
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), mimetype);
getContext().startActivity(intent);
//custumWebView.loadData(stream, "text/html", null);
} catch (Exception exception) {
exception.printStackTrace();
}
}
/**
* Default webview client.
*/
protected class CustomWebViewClient extends WebViewClient {
/**
* Constructor, default.
*/
public CustomWebViewClient () {
}
#Override
public boolean shouldOverrideUrlLoading (WebView view, String url) {
return overrideUrlLoading( view, url );
}
#Override
public void onPageFinished (WebView view, String url) {
pageFinished(view, url);
}
}
protected class CustomDownloadListener implements DownloadListener {
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
downloadStarted(url, mimetype);
}
}
}
and here the xml
<RelativeLayout 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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<WebView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/webView"
android:layout_below="#+id/stream"
android:layout_alignRight="#+id/stream"
android:layout_alignEnd="#+id/stream"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="#+id/imageView" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Home"
android:id="#+id/home"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="stream"
android:id="#+id/stream"
android:layout_alignTop="#+id/home"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Contatti"
android:id="#+id/contatti"
android:layout_above="#+id/webView"
android:layout_centerHorizontal="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:minHeight="50dp"
android:minWidth="400dp" />
</RelativeLayout>
The CustomWebView class is so I don't get errors with loadData for the streaming site. I don't know why this class is working but it is. I copied it from the livestream support site, I'm only a newbie and I'm trying to learn.
If you're referring to these two lines of code at the top of your class:
// Button button = (Button) findViewById(R.id.home);
//final Button //final Button button2 = (Button) findViewById(R.id.contatti);
That will not work in that location. Those buttons are created in your XML layout. You cannot get a reference to a button declared in an XML layout before you first call setContentView() in your onCreate() method. You must do this.
This is what you need to do:
public class MainActivity extends AppCompatActivity {
private Button mButton;
private Button mButton1;
private Button mButton2;
// declare any other fields you require
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button) findViewById(R.id.home);
mButton1 = (Button) findViewById(R.id.stream);
mButton2 = (Button) findViewById(R.id.contatti);
// Your other initialization code
}
Please note that you cannot declare those Buttons as final fields, as they are not instantiated in a constructor (onCreate() is not a constructor).
I have some methods for drawing simple objects using canvas. I need use use it together with xml file storing layout. Here is my code:
public class MainActivity extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new yourCustomView(getApplicationContext());
}
private class yourCustomView extends View {
public yourCustomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.RED);
}
}
}
and there is my layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<package.name.here.yourCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
Why it does not working properly?
Currently, I am trying to build an streaming app using Android NDK and Live555. But my current problem is much more confusing. I've created a CustomPreviewClass to show the actual camera picture. But unfortunatly, when I try to access the view the method findViewById() always returns null. Why? Does anybody have an idea?
Here's my Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
preview = (CameraPreview) findViewById(R.id.surfaceView1); // returns null
if (preview == null) Log.d("Test", "Preview is null");
final Button buttonStart = (Button) findViewById(R.id.buttonStart);
buttonStart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
startRecording();
} catch (IOException e) {
e.printStackTrace();
}
buttonStart.setEnabled(false);
}
});
final Button buttonStop = (Button) findViewById(R.id.buttonStop);
buttonStop.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
stopRecording();
buttonStart.setEnabled(true);
}
});
}
Just a side note: the findViewById() for the buttons works fine...
The activity_main.xml:
<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"
tools:context="de.douglasmedia.LiveCam.MainActivity" >
<de.douglasmedia.LiveCam.views.CameraPreview
android:id="#+id/surfaceView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</de.douglasmedia.LiveCam.views.CameraPreview>
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<Button
android:id="#+id/buttonStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start" >
</Button>
<Button
android:id="#+id/buttonStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop" >
</Button>
</LinearLayout>
The CameraPreview:
...
public CameraPreview(Context context, AttributeSet attrs) {
this(context);
}
public CameraPreview(Context context) {
super(context);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
synchronized (surfaceCreationSync) {
surfaceCreatedHolder = holder;
surfaceCreationSync.notifyAll();
}
}
...
Thanks for your help!
I've solved this problem for my own. The problem was, that the I missed the constructor with 3 arguments in the CameraPreview class. So, I added this constructor and everything works fine...
I'm a newbie to OpenGL on Android and last week I described a problem failing to get the renderer to start for a GLSurfaceView declared in the layout. It starts fine if I declare the renderer in the Activity class and setContentView to it. Here's a simplifed version with all the source code. What am I doing wrong?
Layout . . .
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/dummy"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="a Button" />
<FrameLayout
android:id="#+id/framelay"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.test.rendertest.RTSurface
android:id="#+id/RTSurfaceView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
</LinearLayout>
Activity class. UNcomment the //A's, and comment-out the //B's and the renderer runs. But as shown below the renderer does not run even though its constructor gets called.
public class RenderTest extends Activity {
RTSurface myView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// myView = new RTSurface(this); // A
// setContentView(myView); //A
setContentView(R.layout.main); // B
myView = (com.test.rendertest.RTSurface)findViewById(R.id.RTSurfaceView); //B
}
#Override
protected void onPause() {
super.onPause();
myView.onPause();
}
#Override
protected void onResume() {
super.onResume();
myView.onResume();
}
}
GLSurfaceView . . .
class RTSurface extends GLSurfaceView {
private final RTRenderer renderer;
public RTSurface(Context context) {
super(context);
Log.i("rendertest", "RTSurface constructor - Default Form");
renderer = new RTRenderer();
setRenderer(renderer);
}
public RTSurface(Context context, AttributeSet attrs) {
super(context, attrs);
Log.i("rendertest", "RTSurface constructor - Layout Form");
renderer = new RTRenderer();
setRenderer(renderer);
}
}
. . . and the Renderer (just stubs)
class RTRenderer implements GLSurfaceView.Renderer {
public RTRenderer () {
// a constructor just to have somewhere to set
// breakpoints and logcat messages
Log.i("rendertest", "RTRenderer Constructor");
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.i("rendertest", "onSurfaceCreated in RTRenderer");
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.i("rendertest", "onSurfaceChanged in RTRenderer");
}
public void onDrawFrame(GL10 gl) {
Log.i("rendertest", "onDrawFrame in RTRenderer");
}
}
Thanks in advance!!
You didn't specify your LinearLayout orientation, so it is set to horizontal by default. This means your GLSurfaceView is outside of the screen (because you set your button width to fill_parent).
Just add the following attribute to your LinearLayout :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
I made a simple extension of CheckBoxPreference so that I could have my own custom view with an image icon to the left of the title. The code is below:
public class CustomCheckBoxPreference extends CheckBoxPreference {
private Drawable icon;
public CustomCheckBoxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.CustomCheckBoxPreference, 0, 0);
icon = arr.getDrawable(R.styleable.CustomCheckBoxPreference_icon);
setLayoutResource(R.layout.custom_checkbox_pref);
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView prefsIcon = (ImageView) view.findViewById(R.id.prefs_icon);
prefsIcon.setImageDrawable(icon);
}
The problem is that for some reason the OnPreferenceChangeListener I set to any CustomCheckboxPreference has no effect and is not stored. I tried overriding some of the android methods for the implementation calling super and then printing a line to see what gets called. Notably callChangeListener does not get called. It is this method that leads to the callback for onPreferenceChanged. I tried throwing in a call to onPreferenceChanged inside of setChecked just to see what would happen and the OnPreferenceChangeListener is null:
getOnPreferenceChangeListener().onPreferenceChange(this, checked);
This is how I set the preferencechangelistener:
mTwitterPref.setChecked(!mTwitter.needsAuth());
mTwitterPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
System.out.println("Twitter Preference Changed!");
if ((Boolean) newValue) {
if (mTwitter.needsAuth()) {
System.out.println("We Need To Login To Twitter!");
IntentUtils.startActivityForResult(ProfileAccountsActivity.this,
TwLoginActivity.class, ACTIVITY_OAUTH);
}
} else {
showDialog(DIALOG_LOGOUT_TWITTER);
}
return false;
}
});
I am a bit confused as to why the preferencechangelistener is not working properly as I only overwrite onBindView and the constructor; I call super in both. Any thoughts?
Set android:focusable="false" and android:clickable="false" on the CheckBox:
<CheckBox
android:id="#+android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:clickable="false" />
More info on this thread: Clickable rows on custom ArrayAdapter
I had the same issue with custom button. I tried the solution provided by #jeanh and it works. But my button was not pressed, only area around it was highlighted. Moreover, what if you have a few buttons? Obviously, that this solution won't work. So, I decided to dig deeper and my solution was below:
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/widget_frame" android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="5dp"
android:paddingRight="10dp"
android:paddingBottom="5dp"
>
<!-- define my button -->
<Button android:id="#android:id/title"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="17sp"
android:typeface="sans"
android:textStyle="bold"
android:textColor="#000000"
></Button>
</RelativeLayout>
Java class:
public class ButtonPreference extends Preference {
private final String TAG = getClass().getName();
public interface ButtonListener {
public void onCustomClick();
}
public ButtonListener buttonListener;
public void setButtonListener(ButtonListener buttonListener){
this.buttonListener = buttonListener;
}
public ButtonPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ButtonPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected View onCreateView(ViewGroup parent){
RelativeLayout layout = null;
try {
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (RelativeLayout)mInflater.inflate(R.layout.button_preference, parent, false);
//FIND OUR BUTTON IN LAYOUT
Button button = (Button) layout.findViewById(android.R.id.title);
if(button!=null){
Log.e(TAG, "button found");
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(buttonListener!=null){
buttonListener.onCustomClick(); //INVOKE OUR EVENT!
}
}
});
}
}
catch(Exception e)
{
Log.e(TAG, "Error creating info preference", e);
}
return layout;
}
}
HOW TO USE IT? Simple!
public class WallpaperSettings extends PreferenceActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.prefs);
ButtonPreference defaultSettingsButton = (ButtonPreference) findPreference(EngineCore.pref+"defaultSettings");
defaultSettingsButton.setButtonListener(new ButtonListener() {
#Override
public void onCustomClick() {
Gdx.app.log("ButtonListener", "onCustomClick");
}
});
}
}
I hope it helps someone else.
I found solution !
In my case, I extends DialogPreference to my custom Dialog class,
public class SvDialogPreference extends DialogPreference
I also confuse, because in PreferenceFragment, onPreferenceChange never worked.
SvDialogPreference pref= (SvDialogPreference) findPreference("mainKey");
if( pref != null ) {
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Never execute !
}}
To resolve this. I called "super.callChangeListener" in onDialogClosed.
public class SvDialogPreference extends DialogPreference{
....
#Override
protected void onDialogClosed(boolean positiveResult) {
double InputValue = Double.parseDouble(KEY.getText().toString());
super.callChangeListener(InputValue);
super.onDialogClosed(positiveResult);
}
Now, onPreferenceChange worked fine !