I am trying to add a custom surfaceView class to a surfaceView that has been declared in a xml layout. The problem is that I cannot get the custom class add the the xml defined surfaceView. Some how it just does not start.
This is my code:
MainActivity
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sineWaveSurfaceView = (SineWaveSurfaceView) findViewById(R.id.surfaceView);
}
MainActivity Layout
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<mark.dijkema.android.eindopdracht.SineWaveSurfaceView
android:id="#+id/surfaceView"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_marginTop="20dp" />
<ListView
android:id="#+id/song_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp" >
</ListView>
</RelativeLayout>
SineWaveSurfaceView Class
public class SineWaveSurfaceView extends SurfaceView implements SurfaceHolder.Callback
{
private Context context;
public SineWaveSurfaceView(Context context)
{
super(context);
// TODO Auto-generated constructor stub
this.context = context;
getHolder().addCallback(this);
Log.e("constructor", "done");
}
public SineWaveSurfaceView(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
}
public SineWaveSurfaceView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
protected void OnDraw(Canvas canvas, int value)
{
//canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
float y = Float.valueOf(String.valueOf(value));
for(float x = 0; x < 200; x += 0.1f)
{
canvas.drawPoint(x, y, paint);
}
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder arg0)
{
// TODO Auto-generated method stub
Log.e("start", "started");
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0)
{
// TODO Auto-generated method stub
}
}
The problem is that the Log.e("constructor", "done"); in the constructor of the SineWaveSurfaceView is not even showing up.
What am I doing wrong, because when I do something like
sineWaveSurfaceView = new sineWaveSurfaceView(this);
then it works, but it is not attached to the surfaceView defined in the xml layout.
As veryBadalloc explained in the comments, it appeared that inflating from xml starts the second constructor, thus my code was working after all.
Related
I am trying to draw based on my trace over the screen. In this process my onTouch and OnDraw is not being executed. Could you please assist me to correct this code ?
Xml
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="100"
android:orientation="vertical"
android:background="#ffff0000" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="60"
android:gravity="center" >
<com.example.test2.PathDraw
android:id="#+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="140dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="40"
android:gravity="center" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/lion" />
</LinearLayout>
MainActivity
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PathDraw sineWaveSurfaceView = (PathDraw) findViewById(R.id.surfaceView);
}
}
PathDraw
public class PathDraw extends SurfaceView implements SurfaceHolder.Callback
{
private Context context;
// List<Point> points;
ArrayList<Point> points = new ArrayList<Point>();
public PathDraw(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public PathDraw(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context = context;
getHolder().addCallback(this);
}
public PathDraw(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
protected void OnDraw(Canvas canvas, int value) {
Paint paint = new Paint();
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
Path path = new Path();
boolean first = true;
for(Point point : points){
if(first){
first = false;
path.moveTo(point.x, point.y);
}
else{
path.lineTo(point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
public boolean onTouch(View view, MotionEvent event) {
// if(event.getAction() != MotionEvent.ACTION_DOWN)
// return super.onTouchEvent(event);
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
Log.d("PathDraw", "point: " + point);
return true;
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
}
OnTouch is not called
I also had the exact same problem earlier today.
Class PathDraw should implement OnTouchListener, then set the listener to itself, do something like this:
public class PathDraw extends SurfaceView implements OnTouchListener, SurfaceHolder.Callback{
...
public PathDraw(Context context){
super(context);
setOnTouchListener(PathDraw.this);
}
OnDraw is not called
This post might help:
Android Custom Layout - onDraw() never gets called
Following the instructions here: How to make custom seek bar in android? I was able to make my own custom seekbar that draws text inside the thumb. I know want to create my own seekbar class so that I can call it from my activity. I'm running into problems because when I create a seekbar in my main activity it does not work properly. I don't think I have set up the OnSeek Listener correctly. Here is my main class:
public class MainActivity extends Activity {
CustomSeekBar test;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
test = (CustomSeekBar) findViewById(R.id.seekBar1);
setContentView(R.layout.activity_main);
}
}
Here is my CustomSeekBar class:
public class CustomSeekBar extends SeekBar implements OnSeekBarChangeListener {
String TAG = "TOUCHING";
SeekBar seekbar;
public CustomSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
int value = seekBar.getProgress();
String valueString = value + "";
seekBar.setThumb(writeOnDrawable(R.drawable.thumbler_small, valueString));
Log.d(TAG, "Thumb is being touched");
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public BitmapDrawable writeOnDrawable(int drawableId, String text) {
Bitmap bm = BitmapFactory.decodeResource(getResources(), drawableId)
.copy(Bitmap.Config.ARGB_8888, true);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(20);
Canvas canvas = new Canvas(bm);
canvas.drawText(text, 0, bm.getHeight() / 2, paint);
return new BitmapDrawable(bm);
}
}
Here is my activity_main.xml file:
<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" >
<SeekBar
android:name="com.example.customseekbarclass"
android:id="#+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:indeterminate="false"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:progressDrawable="#drawable/styled_progress"
android:thumb="#drawable/thumbler_small" />
</RelativeLayout>
This is the way my directory is setup:
How do I setup the SeekBar in my main activity class so that it calls the methods from my SeekBar class?
you should switch
test = (CustomSeekBar) findViewById(R.id.seekBar1);
setContentView(R.layout.activity_main);
since R.id.seekBar1 belongs to activity_main.xml otherwise you will get null for test:
setContentView(R.layout.activity_main);
test = (CustomSeekBar) findViewById(R.id.seekBar1);
Then I would change the seekbar part of your layout this way
<com.example.CustomSeekBar
android:id="#+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:indeterminate="false"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:progressDrawable="#drawable/styled_progress"
android:thumb="#drawable/thumbler_small" />
I solved this by calling the OnSeekBarChangeListener from my main activity class:
public class MainActivity extends Activity {
CustomSeekBar test;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
test = (CustomSeekBar) findViewById(R.id.seekBar1);
test.setOnSeekBarChangeListener(test);
}
}
and adding the missing constructors from my CustomSeekBar class:
public class CustomSeekBar extends SeekBar implements OnSeekBarChangeListener {
String TAG = "TOUCHING";
SeekBar mSeekBar;
public CustomSeekBar(Context context) {
super(context);
}
public CustomSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
int value = seekBar.getProgress();
String valueString = value + "";
seekBar.setThumb(writeOnDrawable(R.drawable.thumbler_small, valueString));
Log.d(TAG, "Thumb is being touched");
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
Log.d(TAG, "START");
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
Log.d(TAG, "STOP");
}
public BitmapDrawable writeOnDrawable(int drawableId, String text) {
Bitmap bm = BitmapFactory.decodeResource(getResources(), drawableId)
.copy(Bitmap.Config.ARGB_8888, true);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(20);
Canvas canvas = new Canvas(bm);
canvas.drawText(text, 0, bm.getHeight() / 2, paint);
return new BitmapDrawable(bm);
}
}
I have a main activity class, I've also got a SurfaceView class that starts when my main activity starts.
I've got a seek bar in the main activity. I'd like to send whatever data that the seek bar produces to the SurfaceView to show it, every time it changes.
How can I do that?
Thanks.
Here is my SurfaceView class:
public class SurfaceViewGauge extends SurfaceView implements SurfaceHolder.Callback{
private MySurfaceThread thread;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public SurfaceViewGauge(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public SurfaceViewGauge(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public SurfaceViewGauge(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
setFocusable(true); // make sure we get key events
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {
}
}
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
}
}
And Here is my Thread class:
public class MySurfaceThread extends Thread {
private SurfaceHolder myThreadSurfaceHolder;
private SurfaceViewGauge myThreadSurfaceView;
private boolean myThreadRun = false;
public MySurfaceThread(SurfaceHolder surfaceHolder, SurfaceViewGauge surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}
public void setRunning(boolean b) {
myThreadRun = b;
}
#Override
public void run() {
// TODO Auto-generated method stub
while(myThreadRun){
Canvas c = null;
try{
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder){
myThreadSurfaceView.onDraw(c);
}
sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
in your MainActivity declare a static variable which will hold seekbar value and in your surfaceview code with the help of handler just call that static variable
e.g.
MainClass.seekValue;
In your Code, add Handler..
public Handler mhandler;
public SurfaceViewGauge(Context context, Handler mhandler)
{
super(context);
this.mhandler = mhandler;
// TODO Auto-generated constructor stub
init();
}
In the above code, use the Handler object for sending the code.
I am working on a code where we use canvas to detect the touch on the screen.As of now the canvas is been directly drawn.How to add it as part of a view which comprises of other elements in xml.Here is the code
public class Tutorial2D extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
}
}
Here is the other part of it
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
private ViewThread mThread;
private ArrayList<Element> mElements = new ArrayList<Element>();
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
mThread = new ViewThread(this);
}
public void doDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
synchronized (mElements) {
for (Element element : mElements) {
element.doDraw(canvas);
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (!mThread.isAlive()) {
mThread = new ViewThread(this);
mThread.setRunning(true);
mThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread.isAlive()) {
mThread.setRunning(false);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (mElements) {
mElements.add(new Element(getResources(), (int) event.getX(), (int) event.getY()));
}
return super.onTouchEvent(event);
}
}
How to add this canvas to the main xml and been displayed over an image,any snippet on this or how should I change working on this code,anything will be greatful.Thanks
Try this constructor for the Panel class:
public Panel(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
mThread = new ViewThread(this);
}
You can use the custom view in xml layout with its package name. For example, in main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello" />
<your.package.name.Panel
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Then, in onCreate of your activity:
setContentView(R.layout.main);
While creating a custom Viewgroup,is it possible to have multiple Imagebutton within it?
is it possible to place Image buttons in our own position.
If all these are possible,how to call the click listener which extending this viewgroup?
My ViewGroup have to look like this image
EDIT 1:
public class CustomViewGroup extends ViewGroup{
public CustomViewGroup(Context context) {
super(context);
setWillNotDraw(false);
//addImageView();
// TODO Auto-generated constructor stub
}
public CustomViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
//addImageView();
// TODO Auto-generated constructor stub
}
public CustomViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs,
defStyle);
setWillNotDraw(false);
//addImageView();
// TODO Auto-generated constructor stub
}
#Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
// TODO Auto-generated method stub
System.out.println("onLayout");
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
drawBackground(canvas);
addImageView();
//super.onDraw(canvas);
}
private void drawBackground(Canvas canvas)
{
Bitmap background =BitmapFactory.decodeResource(getContext().getResources(), R.drawable.shape_quarter_circle);
canvas.drawBitmap(background, 0,0, null);
}
private void addImageView()
{
ImageView imageOne = new ImageView(getContext());
imageOne.setImageDrawable(getContext().getResources().getDrawable(R.drawable.round_icon));
//imageOne.setWillNotDraw(false);
addView(imageOne);
requestLayout();
}
I am trying to draw a background and place some ImageView on the top of the background.
In this code Background image is getting displayed correctly. but i could not see the ImageView drawn upon it.
Am i going in the correct path?
all the things you said are possible.
you just use
yourViewGroup.setOnClickListener()
for your view group click listener.