I have to create a custom view in my android application, for that I have wrote code as follows
xml
<com.package.custom.CustomView
android:id="#+id/my_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
CustomView.java
package com.package.custom;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
public class CustomView extends View {
Paint customPaint;
public CustomView(Context context) {
super(context);
customPaint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = this.getMeasuredWidth();
int height = this.getMeasuredHeight();
customPaint.setStyle(Paint.Style.FILL);
customPaint.setAntiAlias(true);
customPaint.setColor(getResources().getColor(android.R.color.holo_blue_dark));
canvas.drawPaint(customPaint);
}
}
Activity
public class CustomViewActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_button);
CustomView customView = (CustomView) findViewById(R.id.my_view);
}
}
but while I am running the application I am getting error ::
3178-3178/com.package.custom E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.package.custom/com.package.custom.CustomViewActivity}: android.view.InflateException: Binary XML file line #11: Error inflating class com.package.custom.CustomView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2255)
What is the reason ? is there any problem in my code ? how do I resolve this ?
Try to change:
public class CustomView extends TextView {
Paint customPaint;
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
customPaint = new Paint();
}
Name of the class constructor are not the same.
View class does not have method android:text="" change base class to TextView
Related
I've created a custom XML layout and I’m trying to draw the map background and the pawn player( the bitmap) over it.
Instead, its painting the pawn player over a white background without the map background that I put as the background on the XML file.
MyViev Class:
package com.example.alpha;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
public class MyView extends View {
Bitmap playerW;
float changingY;
float changingX;
public MyView(Context context) {
super(context);
playerW = BitmapFactory
.decodeResource(getResources(), R.drawable.black);
changingY=0;
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawBitmap(playerW,4+changingX, (canvas.getHeight())-288-changingY, null);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
}
my MainActivity Class:
package com.example.alpha;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
public class MainActivity extends ActionBarActivity {
MyView ourView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ourView = new MyView(this);
setContentView(ourView);
}
}
My XML file:
<?xml version="1.0" encoding="utf-8"?>
<view class="com.example.alpha.MyView"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/mapeasy"
/>
It's because you're not actually setting it to use your XML layout. Instead, you've set the content View to be a new instance of MyView, which doesn't have the XML background property set.
Therefor you have 2 options:
Option 1: Call ourView.setBackgroundDrawable(R.drawable.mapeasy); after you created a new instance of MyView.
or
Option 2: Set the content View to be your actual layout file and then find your MyView by using findViewById(int).
Eg.
public class MainActivity extends ActionBarActivity {
MyView ourView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout_file);
ourView = (MyView)findViewById(R.id.myView);
}
}
This is my Activity class . Here I have a Textview.
I want to Set the TextView from View Class.
public class TestApp extends Activity
{
TextView NameTxtView;
CustomView view;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.Main);
view = (CustomView)findViewById(R.id.customview);
NameTxtView = (TextView) findViewById(R.id.nameTxtxVw);
}
}
This is my View Class. Here i want to set the TextView Text. I can't set this Text on Activity. Because I am getting value on View class.
public class CustomView extends View
{
public CustomView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
public void onDraw(Canvas canvas)
{
NameTxtView.settext("Test");
}
}
Any Idea how to do that?
thanks
Do this way
TestApp.java
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import com.example.demo.CustomView.CustmViewListener;
public class TestApp extends Activity
{
TextView NameTxtView;
CustomView view;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.Main);
view = (CustomView)findViewById(R.id.customview);
NameTxtView = (TextView) findViewById(R.id.nameTxtxVw);
view.setCustmViewListener(new CustmViewListener() {
#Override
public void onUpdateValue(String updatedValue) {
NameTxtView.setText(updatedValue);
}
});
}
}
CustomView.java
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
public class CustomView extends View {
CustmViewListener custmViewListener;
public CustmViewListener getCustmViewListener() {
return custmViewListener;
}
public void setCustmViewListener(CustmViewListener custmViewListener) {
this.custmViewListener = custmViewListener;
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onDraw(Canvas canvas) {
if (getCustmViewListener() != null) {
getCustmViewListener().onUpdateValue("passYourValueHere");
}
}
public interface CustmViewListener {
void onUpdateValue(String updatedValue);
}
}
Try like this :
In CustomView Constructor call LayoutInflaterService and pass Id for your Layout & TextView :
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(LAYOUT_INFLATER_SERVICE);
final RelativeLayout yourLayout = (RelativeLayout) layoutInflater.inflate(R.layout.dialog_menu, null);
TextView myText = (TextView) yourLayout.findViewById(R.id.nameTxtxVw);
myText.setText("");
Your problem is that the activity class has a context and your second one does not. To solve this create a global variable: static Activity activity and initialize it in the constructor.
Then call: new CustomClass(ActivityClass.this).
Next whenever you want to do something related to an activity simply put activity. in front of stuff
I am trying to overlay a drawing on top of a camera preview. I made two custom class extended from SurfaceView: one for the overlay, and one for the cam.
Here is my logcat (only the "Caused by" statements) :
04-11 19:58:06.549: W/dalvikvm(867): threadid=1: thread exiting with uncaught exception (group=0x40a71930)
04-11 19:58:06.609: E/AndroidRuntime(867): Caused by: android.view.InflateException: Binary XML file line #5: Error inflating class com.example.gui_v9.Activity1.CamView
04-11 19:58:06.609: E/AndroidRuntime(867): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.gui_v9.Activity1.CamView" on path: /data/app/com.example.gui_v9-2.apk
The second error where it cannot find the class, is because it did not inflate.
Eclipse Graphical Layout successfully compiles the xml code and gives a decent preview. Here is my XML code:
<?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">
<com.example.gui_v9.Activity1.CamView
android:id="#+id/camview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<com.example.gui_v9.Activity1.OverlayView
android:id="#+id/overlay"
android:layout_width="200dp"
android:layout_height="200dp"/>
</FrameLayout>
I tried to change the flags from
<com.example.gui_v9.Activity1.OverlayView .../>
to
<com.example.gui_v9.Activity1.OverlayView ...></com.example.gui_v9.Activity1.OverlayView>
or to
<SurfaceView class="com.example.gui_v9.Activity1$OverlayView" ... />
or even
<SurfaceView class="com.example.gui_v9.Activity1$OverlayView" ... ></SurfaceView>
without luck. In the latter case, I have a casting problem (CamView cannot be casted in SurfaceView) and Eclipse's XML Graphical Layout fails to render, so I m guessing that the first one takes me further in the compiling process.
You may also take a look at my main activity:
package com.example.gui_v9;
import java.io.IOException;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.hardware.Camera;
public class Activity1 extends Activity {
CamView camview = null;
OverlayView overlay = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1);
camview = (CamView) findViewById(R.id.camview);
overlay = (OverlayView) findViewById(R.id.overlay);
overlay.getHolder().setFormat(PixelFormat.TRANSLUCENT);
}
public static class CamView extends SurfaceView implements SurfaceHolder.Callback {
Camera cam = null;
SurfaceHolder camviewholder = null;
public CamView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public CamView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public CamView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
if (cam!=null) {
try {
cam.setPreviewDisplay(camviewholder);
}
catch (IOException e) {
}
cam.startPreview();
}
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
cam = Camera.open();
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
cam.stopPreview();
cam.release();
}
}
public static class OverlayView extends SurfaceView implements SurfaceHolder.Callback {
private Paint paint = new Paint();
OverlayThread overlaythread = null;
public OverlayView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public OverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public OverlayView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
canvas.drawCircle(100, 100, 100, paint);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
setWillNotDraw(false); //Allows us to use invalidate() to call onDraw()
overlaythread = new OverlayThread(getHolder(), this);
overlaythread.setRunning(true);
overlaythread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
try {
overlaythread.setRunning(false);
overlaythread.join();
}
catch (InterruptedException e) {
}
}
}
public static class OverlayThread extends Thread {
private OverlayView overlay;
private SurfaceHolder overlayholder;
private boolean _run = false;
public OverlayThread(SurfaceHolder _overlayholder, OverlayView _overlay) {
overlayholder = _overlayholder;
overlay = _overlay;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = overlayholder.lockCanvas(null);
synchronized (overlayholder) {
overlay.invalidate();
}
}
finally {
if (c != null) {
overlayholder.unlockCanvasAndPost(c);
}
}
}
}
}
}
As you can see, I have the three constructors for each classes (with 1,2 and 3 arguments) which is a common error in inflating class failure.
I got this to work when I implemented CamView and OverlayView in two separate classes (CamView.java and OverlayView.java), respectively. So I don't understand why importing classes makes it work. Maybe something with the static workspace?
Thank yall for your help!
I have this extension of SeekBar:
package com.simplemathgame;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class SeekBarPlus extends SeekBar implements OnSeekBarChangeListener{
private TextView numberOfDrills;
public SeekBarPlus(Context context) {
super(context);
}
public SeekBarPlus(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SeekBarPlus(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
Log.w("SeekBarChanged", "change to" + progress);
numberOfDrills.setText(String.valueOf(progress));
}
public void setTextView(TextView textView){
numberOfDrills = textView;
Log.w("SeekBar", "text to bar");
}
}
And here is the main activity code:
package com.simplemathgame;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import com.simplemathgame.SeekBarPlus;
public class MainActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SeekBarPlus addSeekBar = (SeekBarPlus) findViewById(R.id.add_seek_bar);
SeekBarPlus subSeekBar = (SeekBarPlus) findViewById(R.id.sub_seek_bar);
SeekBarPlus mulSeekBar = (SeekBarPlus) findViewById(R.id.mul_seek_bar);
SeekBarPlus divSeekBar = (SeekBarPlus) findViewById(R.id.div_seek_bar);
TextView numberOfAddDrills = (TextView) findViewById(R.id.add_drills_number);
TextView numberOfSubDrills = (TextView) findViewById(R.id.sub_drills_number);
TextView numberOfMulDrills = (TextView) findViewById(R.id.mul_drills_number);
TextView numberOfDivDrills = (TextView) findViewById(R.id.div_drills_number);
addSeekBar.setTextView(numberOfAddDrills);
subSeekBar.setTextView(numberOfSubDrills);
mulSeekBar.setTextView(numberOfMulDrills);
divSeekBar.setTextView(numberOfDivDrills);
}
}
After I move the progress bar nothing happens, I have all the needed elements (TextViews).
I would like:
I would like the SeekBarPlus Automatically listen to it's changes and react as I have coded in the onProgressChanged method,in other words I would like that onProgressChanged would be triggered without any code in the main activity.
Screenshot
After reading the documentation:
Clients of the SeekBar can attach a SeekBar.OnSeekBarChangeListener to
be notified of the user's actions.
You need to have a listener on your Seekbar in order to update.
Update
This is possible, but you have to create a single view to house everything and then attach it it that way. Once you have created this, then add the custom view to your layout file. Then add callbacks as necessary from your custom view. Of course this implies that you added your listeners IN your custom view class.
Example
You would have something like this in your class, make sure to set the orientation of the views:
package com.blah.my.package
class MyCustomClass extends LinearLayout{
CustomSeekbar v1 ...
CustomSeekbar v2 ...
CustomSeekbar v3 ...
CustomSeekbar v4 ...
CustomSeekbar v5 ...
CustomSeekbar v6 ...
...
Constructors and methods n' stuff...
}
Once you have this, then in your layout XML:
<?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">
<com.blah.my.package.MyCustomClass ... />
...
<LinearLayout>
To learn more:
http://developer.android.com/training/custom-views/index.html
The easiest way is to implement OnSeekBarChangeListener directly on your extended class:
public class SeekBarPlus extends SeekBar implements OnSeekBarChangeListener{
public SeekBarPlus(Context context) {
super(context);
setOnSeekBarChangeListener(this);
}
public SeekBarPlus(Context context, AttributeSet attrs) {
super(context, attrs);
setOnSeekBarChangeListener(this);
}
public SeekBarPlus(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setOnSeekBarChangeListener(this);
}
....
}
Otherwise none of the on* methods will get called. Note: this really should be a composite widget and you shouldn't need to be passing in the TextView.
You also need to do what Sergio suggested and not use the int value directly: numberOfDrills.setText("" + progress);
That's because you're sending an int to setText(), so it doesn't work because it expects a String. Change the line to:
numberOfDrills.setText("" + progress);
Or:
numberOfDrills.setText(String.valueOf(progress));
You may want to change this 4 lines too in your MainActivity, you are setting 4 TextViews to the same seekbar:
/*addSeekBar.setTextView(numberOfAddDrills);
addSeekBar.setTextView(numberOfSubDrills);
addSeekBar.setTextView(numberOfMulDrills);
addSeekBar.setTextView(numberOfDivDrills);*/
addSeekBar.setTextView(numberOfAddDrills);
subSeekBar.setTextView(numberOfSubDrills);
mulSeekBar.setTextView(numberOfMulDrills);
divSeekBar.setTextView(numberOfDivDrills);
I am trying to develop a tiny android app that just opens a browser to a website. I am using mac OS 10.6 and the latest android/eclipse tools. But I keep getting this exception:
11-29 13:03:55.113: E/AndroidRuntime(1012): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mycomp/com.mycomp.pack}: android.view.InflateException: Binary XML file line #7: Error inflating class com.mycomp.MyTextView
Here is my code:
package com.mycomp;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class myapp extends Activity {
/** Called when the activity is first created. */`
private MyTextView myview;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("onCreate", "onCreate ");
myview = (MyTextView)findViewById(R.id.myview);
myview.setParent(this);
}
public static class MyTextView extends TextView {
private View mLastVisChangedView;
private int mLastChangedVisibility;
private Activity parent;
public void setParent(Activity p){
parent =p;
}
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public View getLastVisChangedView() {
return mLastVisChangedView;
}
public int getLastChangedVisibility() {
return mLastChangedVisibility;
}
#Override
protected void onVisibilityChanged(View changedView, int visibility){
Log.d("onVisibilityChanged", "new vis == " + visibility);
if (parent !=null && visibility == View.VISIBLE){
parent.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.mysite.com")));
parent.moveTaskToBack(true);
}
}
}
}
<?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" >
<com.mycomp.MyTextView
android:id="#+id/myview"
android:text="#string/hello"/>
</LinearLayout>
The type would be com.mycomp.myapp.MyTextView. (Or $ since it's an inner class?)
You may also need to specify the view as follows:
<view class="com.mycomp.myapp$MyEditText" ...
I don't think you need an onFinishInflate in this case.
You should put the MyTextView class in a separate file. Then com.mycomp.MyTextView would be correct.