I am trying to code a touchscreen interactive drawing application inside android studios with a fragment; however, I am receiving an error of but fails to find what it is caused by and how to fix it. I am a beginner to app development and simply was following a tutorial. See the link below and please notify me if you need additional information. Thank you so much in advance!
I suspect it is caused by the package name in the xml file or the constructors in the java file!
Problems/Errors
at
com.app2016.alexker.matchplanning.MatchPlanning.onCreateView(MatchPlanning.java:67)
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.app2016.alexker.matchplanning/com.app2016.alexker.matchplanning.MainActivity}:
android.view.InflateException: Binary XML file line #19: Error
inflating class com.codepath.example.simpledrawapp.SimpleDrawingView
Java Class
package com.app2016.alexker.matchplanning;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;
import android.util.AttributeSet;
/**
* Created by AlexKer on 16-02-06.
*/
public class SimpleDrawingView extends View {
//set up initial paint color
private final int paintColor = Color.BLACK;
//defines paint and canvas
private Paint drawPaint;
//path
private Path path = new Path();
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, drawPaint);
}
public SimpleDrawingView(Context context){
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
setupPaint();
}
public SimpleDrawingView(Context context, AttributeSet attrs){
super(context, attrs);
/*setFocusable(true);
setFocusableInTouchMode(true);
setupPaint();*/
}
private void setupPaint() {
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(5);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
}
// Get x and y and append them to the path
public boolean onTouchEvent(MotionEvent event) {
float pointX = event.getX();
float pointY = event.getY();
// Checks for the event that occurs
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Starts a new line in the path
path.moveTo(pointX, pointY);
break;
case MotionEvent.ACTION_MOVE:
// Draws line between last point and this point
path.lineTo(pointX, pointY);
break;
default:
return false;
}
postInvalidate(); // Indicate view should be redrawn
return true; // Indicate we've consumed the touch
}
}
Below is the onCreateView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_match_planning, container, false);
return view;
}
And XML
<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:id="#+id/fragment_match_plan"
android:orientation="vertical"
android:gravity="center|top"
tools:context="com.app2016.alexker.matchplanning.MatchPlanning"
android:background="#drawable/field">
<!-- TODO: Update blank fragment 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"
tools:context=".MainActivity" >
<com.codepath.example.simpledrawapp.SimpleDrawingView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/SimpleDrawingView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
Actually, the package name is also wrong in XML. Should be
com.app2016.alexker.matchplanning.
I have no idea what the view is you're trying to use, but this seems super unusual:
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
Try this:
<com.app2016.alexker.matchplanning.SimpleDrawingView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/SimpleDrawingView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Also -- currently, the LinearLayout or RelativeLayout is useless.
Related
I am following this tutorial into making an app for Android and ran into a problem. Disclaimer: I know next to nothing about Java or Eclipse, so bear with me.
I created a bitmap, which I put into an ImageView(?), and now the tutorial says to add the ImageView to the root_layout, but to be fair, I have no idea what the root_layout is (I Googled some, but couldn't find the right answer). Also, Eclipse gives me the 'layoutroot cannot be resolved or is not a field'-error, which I do not know how to solve. My question then is, how do I get the image to display on the screen? Thanks in advance :-)
Here is my (full) code:
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class ShowImage extends ActionBarActivity {
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.show_image, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
// shows the activity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_image);
try {
// load large image from resources
Bitmap game_image = BitmapFactory.decodeResource(this.getResources(), R.drawable.sample_0);
// create cropped image from loaded image
Bitmap cropped = Bitmap.createBitmap(game_image, 0, 0, 100, 100);
// no longer need larger image
game_image.recycle();
// create ImageView to display image
ImageView imageView = new ImageView(this);
imageView.setImageBitmap(cropped);
// add ImageView to root layout
LinearLayout root = (LinearLayout)this.findViewById(R.id.root_layout);
root.addView(imageView);
}
// catch comes here
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
// shows GamePlay-activity after three seconds
Intent intent = new Intent(ShowImage.this, GamePlay.class);
ShowImage.this.startActivity(intent);
ShowImage.this.finish();
}
}, 3000);
}
}
Added .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: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="nl.mprog.projects.nPuzzle10206353.ShowImage" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wait three seconds..." />
</RelativeLayout>
root_layout is basically the existing layout in your xml in which you want to add newly created View.
Assign id root_layout to the RelativeLayout in your xml file.
OR
Keep a new Layout inside it with root_layout id.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root_layout"
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="nl.mprog.projects.nPuzzle10206353.ShowImage" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wait three seconds..." />
</RelativeLayout>
So now when you use this in Activity:
RelativeLayout root = (RelativeLayout)this.findViewById(R.id.root_layout);
root.addView(imageView);
imageView would be added to that RelativeLayout with id root_layout
add the imageView to your xml:
<ImageView android:id="#+id/mImageView"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:contentDescription="solecito"
android:layout_weight = "1"
android:layout_gravity="center"
/>
then add it on you onCreate Method
ImageView im = (ImageView)findViewById(R.id.mImageView);
after you can add the image
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
im.setImageBitmap(bitmap);
package com.tommymacwilliam.androidwalkthroughapp3;
import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.ImageView;
import android.widget.Toast;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class AndroidWalkthroughApp3 extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
// load large image from resources
Bitmap background = BitmapFactory.decodeResource(this.getResources(), R.drawable.puzzle_0);
// create cropped image from loaded image
Bitmap cropped = Bitmap.createBitmap(background, 0, 0, 230, 230);
// no longer need larger image
background.recycle();
// create ImageView to display image
ImageView imageView = new ImageView(this);
imageView.setImageBitmap(cropped);
// add ImageView to root layout
LinearLayout root = (LinearLayout)this.findViewById(R.id.root_layout);
root.addView(imageView);
int screenWidth = this.getResources().getDisplayMetrics().widthPixels;
Toast.makeText(this, String.valueOf(screenWidth), Toast.LENGTH_LONG).show();
}
catch (OutOfMemoryError e) {
// uh oh.
}
}
}
In my current project I run into an dead end. My custom view, only created to show a specific color, won't show in the view of my emulator (although it seems to show up correctly in the editor of Eclipse) except if it had a minimum height, but then it only get this exact height. I want it to match_parent.
The problem might be that it is in the item layout of a list view.
That's the code of my Custom View:
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class ColorView extends View {
private int mColor;
private Context mContext;
private int width;
private int height;
public ColorView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ColorView, 0, 0);
try {
mColor = a.getColor(R.styleable.ColorView_color, 0xFFFFFF);
} finally {
a.recycle();
}
}
public void setColor(int hexColor) {
mColor = hexColor;
invalidate();
}
public void setColorFromResource(int resID) {
mColor = mContext.getResources().getColor(resID);
invalidate();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.d("DEBUG", Integer.toString(w) + " " + Integer.toString(h));
width = w;
height = h;
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(mColor);
Log.d("DEBUG", "drawn");
}
}
And a simplified version of my layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:raabeapp="http://schemas.android.com/apk/res/com.example.myapp"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/row_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.example.myapp.ColorView
android:id="#+id/status_view"
android:layout_width="20dip"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dip"
android:minHeight="50dp"
raabeapp:color="#FF0000" />
<TextView
android:id="#+id/hour_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/status_view"
android:text="1"
android:textSize="#dimen/hour_textsize"
android:width="70dp" />
<TextView
android:id="#+id/text_hourtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/hour_view"
android:text="#string/hour_text"
android:textSize="#dimen/hourtext_textsize" />
Ok, I figured out a workaround:
When I use a LinearLayout instead of a RelativeLayout I get the result I want.
It seems that the problem lies in the RelativeLayout. If someone knows why this is, or how I could still use a RelativeLayout I would be very interested. This answer does not provide a full solution, but in case someone runs into my problem it could provide a ugly workaround.
Use android:layout_height="match_parent" for your RelativeLayout.
[EDIT]: Thank you for all the meaningful answers, the problem is now solved, thank to your help. Similar issue: Android: I am unable to have ViewPager WRAP_CONTENT
I'm trying to implement the UI of my app : I want a ListView with a ViewPager in each row.
Here are my files :
MainActivity.java
package com.condi;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.Menu;
public class MainActivity extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setListAdapter(new CardListAdapter(this, getFragmentManager()));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
CardListAdapter.java
package com.condi;
import java.util.List;
import android.app.FragmentManager;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class CardListAdapter extends BaseAdapter {
private Context context;
private FragmentManager fragmentManager;
private List<Profile> profiles;
CardListAdapter(Context context, FragmentManager fragmentManager) {
this.context = context;
this.fragmentManager = fragmentManager;
this.profiles = new DatabaseHelper(context).getProfiles();
}
#Override
public int getCount() {
return profiles.size();
}
#Override
public Profile getItem(int position) {
return profiles.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = View.inflate(context, R.layout.profile_card, null);
CardPagerAdapter mCardPagerAdapter = new CardPagerAdapter(
fragmentManager);
ViewPager viewPager = (ViewPager) convertView.findViewById(R.id.pager);
viewPager.setAdapter(mCardPagerAdapter);
viewPager.setId(R.id.pager);
return convertView;
}
}
profile_card.xml (issue came from wrap_content).
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="4dp"
android:background="#drawable/card_background"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
CardPagerAdapter.java
package com.condi;
import android.app.Fragment;
import android.app.FragmentManager;
import android.support.v13.app.FragmentPagerAdapter;
public class CardPagerAdapter extends FragmentPagerAdapter {
public CardPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new Fragment1();
case 1:
return new Fragment2();
}
return null;
}
#Override
public int getCount() {
return 2;
}
}
Fragment1.java
package com.condi;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment1 extends Fragment {
public Fragment1() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.preference_category, container, false);
}
}
Fragment2.java
package com.condi;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment2 extends Fragment {
public Fragment2() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.preference_category, container, false);
}
}
The database that furnishes the profiles is working well.
The problem is that I am getting an empty list with the correct number of item, but no ViewPager displayed at all. screenshot of my app
What am I doing wrong ?
Try to change your ViewPager's height in xml. wrap_content does not work.
To make is clear, its a bad practice to use viewpagers inside a list view as this design hits the ui performance. The best way to handle this problem is:
To do manual inflation of viewpagers and add to a layout.
Add a unique id to each viewpager so that it is identified uniquely by the system.
Extend a custom viewpager and onmeasure() measure the child layout inflated at the page selected. You can do this by setting a callback in your custom viewpager and trigger the callback from viewpagers onPageScrolled listener, passing the position to identify the child layout.
In your onMeaure() method measure the child layout height and set it as the viewpagers height using super.onMeasure() passing the newly measured specs.
Key points to make a note of :
N.B. Set a unique id to the viewpager inflated by you.
try this problem in layout height
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="4dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="4dp"
android:background="#drawable/card_background"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</FrameLayout>
It's a bad practice to use wrap_content for your viewpager's height. You can use match_parent or a static dp for your viewpager's height.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="4dp"
android:background="#drawable/card_background"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</FrameLayout>
If it's a must to use wrap_content for your viewpager's height you can override your viewpager's onMeasure() and calculate height. Here's an example below about it.
Android: I am unable to have ViewPager WRAP_CONTENT
I hope this'll help you.
ViewPager doesn’t support wrap_content as it stands now because it doesn’t load all of its children at the same time, meaning it can’t get an appropriate measurement. You must fix View's height in your xml or create a custom ViewPager (read more at here) and use it in your xml
Try using a fixed height ViewPager inside the ListView.ViewPager does not support wrap_content
I was wondering if there's any tutorial having a drag and drop functionality on differing images making them target specific?
By this I mean, If you have say, 4 draggable images; image_drag_1, image_drag_2, image_drag_3, and image_drag_4 and 4 drop_target images; image_drop_1, image_drop_2, image_drop_3 and image_drop_4.
image_drag_1 should be matched to image_drop_1 and any attempt to drop image_drag_1 on any other drop image or location in the screen layout, makes image_drag_1 snap back to its original position.
This tutorial implements a drag drop functionality for textview, though not target specify.
I have tried on my own implementing my own drag and drop following the tutorual stated above, leaving textview to be draggable and the imageviews, the drop targets. It just crashes my emulator.
Below can be found my .java file:
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.TextView;
import android.content.ClipData;
import android.graphics.Typeface;
public class MainActivity extends Activity {
//Imageview to drag the image is dragged into
private ImageView image1, image2;
//textview the image is dragged into
private TextView choice1, choice2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//views to drag
image1 = (ImageView)findViewById(R.id.imageView1);
image2 = (ImageView)findViewById(R.id.imageButton1);
//views to drop onto
choice1 = (TextView)findViewById(R.id.choice_1);
choice2 = (TextView)findViewById(R.id.choice_2);
//set touch listeners
image1.setOnTouchListener(new ChoiceTouchListener());
image2.setOnTouchListener(new ChoiceTouchListener());
//set drag listeners
choice1.setOnDragListener(new ChoiceDragListener());
choice2.setOnDragListener(new ChoiceDragListener());
}
private final class ChoiceTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
/*
* Drag details: we only need default behavior
* - clip data could be set to pass data as part of drag
* - shadow can be tailored
*/
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
//start dragging the item touched
view.startDrag(data, shadowBuilder, view, 0);
return true;
} else {
return false;
}
}
}
/**
* DragListener will handle dragged views being dropped on the drop area
* - only the drop action will have processing added to it as we are not
* - amending the default behavior for other parts of the drag process
*
*/
private class ChoiceDragListener implements OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
//no action necessary
break;
case DragEvent.ACTION_DRAG_ENTERED:
//no action necessary
break;
case DragEvent.ACTION_DRAG_EXITED:
//no action necessary
break;
case DragEvent.ACTION_DROP:
//handle the dragged view being dropped over a drop view
View view = (View) event.getLocalState();
//stop displaying the view where it was before it was dragged
view.setVisibility(View.INVISIBLE);
//view dragged item is being dropped on
TextView dropTarget = (TextView) v;
//view being dragged and dropped
ImageView dropped = (ImageView) view;
//update the text in the target view to reflect the data being dropped
dropTarget.setText(dropped.getImageAlpha());
//make it bold to highlight the fact that an item has been dropped
dropTarget.setTypeface(Typeface.DEFAULT_BOLD);
//if an item has already been dropped here, there will be a tag
Object tag = dropTarget.getTag();
//if there is already an item here, set it back visible in its original place
if(tag!=null)
{
//the tag is the view id already dropped here
int existingID = (Integer)tag;
//set the original view visible again
findViewById(existingID).setVisibility(View.VISIBLE);
}
//set the tag in the target view being dropped on - to the ID of the view being dropped
dropTarget.setTag(dropped.getId());
break;
case DragEvent.ACTION_DRAG_ENDED:
//no action necessary
break;
default:
break;
}
return true;
}
}
}
My xml file is as below:
<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" >
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="66dp"
android:orientation="vertical"
android:padding="10dp"
android:paddingLeft="50dp"
android:paddingRight="50dp" >
<TextView
android:id="#+id/choice_1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_marginTop="46dp"
android:background="#drawable/choice"
android:gravity="center"
android:text="#string/choice_1" />
<TextView
android:id="#+id/choice_2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_marginTop="57dp"
android:background="#drawable/choice"
android:gravity="center"
android:text="#string/choice_2" />
</LinearLayout>
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/linearLayout1"
android:layout_marginBottom="16dp"
android:layout_toRightOf="#+id/imageButton1"
android:contentDescription="#string/image_desc"
android:src="#drawable/firefighter" />
<ImageButton
android:id="#+id/imageButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:contentDescription="#string/image_desc"
android:src="#drawable/clown" />
Any advise as to what I'm doing wrong? Thanks in advance.
I'm trying to create an element within a ListView which displays a few TextViews and a custom view in which I plan to draw to the canvas by overriding onDraw(). The method I'm attempting works fine with just the TextViews, but fails when I try and use the custom element (Graph), so the problem definitely lies here.
I have the following XML file which I use as the layout for each ListView item:
year_row.xml:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/year_row_linear"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="6dp"
>
<TextView android:id="#+id/year_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dip"
android:textColor="#android:color/white"
/>
<com.android.gradetracker.Graph android:id="#+id/year_graph"
android:layout_width="fill_parent"
android:layout_height="50dip"
/>
<TextView android:id="#+id/year_average"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#android:color/white"
/>
<TextView android:id="#+id/year_progress"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
My Graph class is as follows:
Graph.java:
package com.android.gradetracker;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;
public class Graph extends View {
public Graph(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
// to test if it works
canvas.drawColor(Color.WHITE);
super.onDraw(canvas);
}
}
My main class which sets up the elements of the ListView then contains the following code:
private ArrayList <HashMap<String,Object>> list = new ArrayList <HashMap<String,Object>>();
private SimpleAdapter adapter;
private ListView listView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
listView = (ListView) findViewById(R.id.listview);
listView.setClickable(true);
String[] from = {"name", "graph", "average", "progress"};
int[] to = new int[] {R.id.year_name, R.id.year_graph, R.id.year_average, R.id.year_progress};
adapter = new SimpleAdapter(this.getApplicationContext(), list, R.layout.year_row, from, to);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
public void addYear(String name) {
Graph graph = new Graph(this);
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("name", name);
map.put("graph", graph);
map.put("average", "--%");
map.put("progress", "--/--%");
list.add(map);
adapter.notifyDataSetChanged();
}
As I said, removing all references to the Graph class, the application works fine. I'm just having trouble getting Graph to display.
Logcat gives the error:
08-04 17:09:50.415: ERROR/AndroidRuntime(397): android.view.InflateException: Binary XML file line #16: Error inflating class com.android.gradetracker.Graph
Thanks for any help in advance.
Okay, the main problem seemed to be that SimpleAdaptor does not allow you to use custom views. I had to create a custom adaptor which extends BaseAdapter in order to display the custom view, with the following code for the getView() method:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.year_row, parent, false);
}
TextView name = (TextView) convertView.findViewById(R.id.year_name);
Graph graph = (Graph) convertView.findViewById(R.id.year_graph);
TextView average = (TextView) convertView.findViewById(R.id.year_average);
TextView progress = (TextView) convertView.findViewById(R.id.year_progress);
ArrayList<Object> row = list.get(position);
name.setText(String.valueOf(row.get(0)));
graph = (Graph)row.get(1);
average.setText(String.valueOf(row.get(2)));
progress.setText(String.valueOf(row.get(3)));
return convertView;
}
You need a constructor in your Graph class.
Start By calling super
Change the onDraw function of the Graph class
#Override
protected void onDraw(Canvas canvas) {
//start with super
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
}