I have a simple listView via a custom adapter. Each row in the list view is composed of a ImageButton and TextView.
The idea is to change the ImageButton when user taps on it and it does not work. However, ImageButton changes for the views that are scrolled and recycled. I mean, when user scrolls down the list and comes back to the top and tap on the ImageButton it works as expected for those rows that were scrolled and back again.
Can you guys help me out what i'm missing? I'm extremely new to Android and have been stuck around this for about a week now trying to fix this.
Here's the APK for the sample test app:
https://www.dropbox.com/s/pzlahtqkgj010m8/app-ListViewExample.apk?dl=0
Here are the relevant parts of my code:
avtivity_main.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">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listView"
/>
</RelativeLayout>
and to render the single row in the ListView the following xml is utilized:
single_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageButton"
android:src="#drawable/b"
android:layout_weight="2"
style="#style/ListView.first"
android:layout_gravity="center"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/textView"
android:layout_weight="10"
android:layout_gravity="center"
/>
</LinearLayout>
coming to the Java code,
MainActivity.java is
public class MainActivity extends AppCompatActivity {
String[] titles;
ListView list;
private listViewAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Resources res = getResources();
titles = res.getStringArray(R.array.titles);
list = (ListView) findViewById(R.id.listView);
adapter = new listViewAdapter(this, titles);
list.setAdapter(adapter);
}
}
and the custom adapter listViewAdapter.java look like this
class sListItem {
public ImageButton button;
public TextView text;
public boolean active;
}
public class listViewAdapter extends ArrayAdapter<String> {
private final String[] titles;
Context context;
private int size = 15;
public sListItem mp[] = new sListItem[size];
public listViewAdapter(Context context, String[] titles) {
super(context, R.layout.single_row, R.id.imageButton, titles);
this.context = context;
this.titles = titles;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.single_row, parent, false);
if(mp[position] == null)
mp[position] = new sListItem();
mp[position].button = (ImageButton) row.findViewById(R.id.imageButton);
mp[position].button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mp[position].active = !mp[position].active;
setIcon(position, mp[position].active);
}
});
mp[position].text = (TextView) row.findViewById(R.id.textView);
mp[position].text.setText(titles[position]);
setIcon(position, mp[position].active);
return row;
}
private void setIcon(int position, boolean active) {
Drawable drawable;
if(active){
drawable = getContext().getResources().getDrawable(R.drawable.a);
} else {
drawable = getContext().getResources().getDrawable(R.drawable.b);
}
mp[position].button.setImageDrawable(drawable);
}
}
EDIT: Added link to sample test app.
You should tell adapter to update by calling notifydatasetchanged in the click listener
mp[position].button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mp[position].active = !mp[position].active;
setIcon(position, mp[position].active);
notifydatasetchanged();
}
});
Related
I'm new to Android Studio and coding in general and I am trying to display a custom ListView with an image of a colour and the name of the colour. I have used a custom Adapter to inflate the view with two arrays containing the drawable image colours and string of the names.
The problem I am having - the custom adapter is only displaying the layers from position 1 and onwards. For example, where the first layer should be img_01 and "red" - it is displaying img_02 and "Orange".
I've tried debugging the code and it seems that though the adapter is setting the values for position 0, but I cannot find the reason why it is not displaying (as the others are displaying fine).
The images & names are just placeholders, so an alternative solution that doesn't include both the drawables and names wouldn't be viable,
Thank you in advance
CustomAdapter.java
public class CustomAdapter extends BaseAdapter {
Context context;
int[] images;
String[] colour;
LayoutInflater mInflater;
public CustomAdapter(Context c, int[] i, String[] col) {
this.context = c; //sets the application context that has been passed to the adapter
this.images = i; //sets the images array that has been passed to the adapter
this.colour = col; //sets the colour array that has been passed to the adapter
mInflater = (LayoutInflater.from(context)); //sets the layout inflater from context
}
#Override
public int getCount() { //total number of elements in the array
return images.length;
}
#Override
public Object getItem(int position) { //gets the item using the position
return null;
}
#Override
public long getItemId(int position) { //gets the item position
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) { //this is used to update the view
convertView = mInflater.inflate(R.layout.custom_layout, null);
ImageView image = convertView.findViewById(R.id.imageView);
TextView text = convertView.findViewById(R.id.textView);
text.setText(colour[position]);
image.setImageResource(images[position]);
return convertView;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
ListView mListView;
int[] images = {R.drawable.img01,
R.drawable.img02,
R.drawable.img03,
R.drawable.img04};
String[] colour = {"Red",
"Orange",
"Yellow",
"Green"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = findViewById(R.id.listView);
CustomAdapter customAdapter = new CustomAdapter(getApplicationContext(), images, colour);
//passes information of images and application context to the item adapter
mListView.setAdapter(customAdapter);
//sets the adapter to the listview
}
}
custom_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginStart="7dp"
android:layout_marginLeft="7dp"
android:layout_marginTop="9dp"
app:srcCompat="#drawable/img01" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginStart="99dp"
android:layout_marginLeft="99dp"
android:layout_marginTop="36dp"
android:text="colourName" />
</RelativeLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="#+id/listView"
android:layout_width="409dp"
android:layout_height="729dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Try to set the height of the ListView to wrap_content instead of hardcoding it
<ListView
...
android:layout_height="wrap_content"/>
You can do it with RecyclerView.
Create a custom class
public class ExampleItem {
private int mImageResource; //your color image
private String mText1; //your text
public ExampleItem(int imageResource, String text1) {
mImageResource = imageResource;
mText1 = text1;
}
public int getImageResource() {
return mImageResource;
}
public String getText1() {
return mText1;
}
}
Create a XML layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
app:cardCornerRadius="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp">
<ImageView
android:id="#+id/imageView"
android:layout_width="50dp"
android:layout_height="50dp"
android:padding="2dp" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toEndOf="#+id/imageView"
android:text="Line 1"
android:textColor="#android:color/black"
android:textSize="20sp"
android:textStyle="bold" />
</RelativeLayout>
</android.support.v7.widget.CardView>
Create a Recycler View Adapter
public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder> {
private ArrayList<ExampleItem> mExampleList;
public static class ExampleViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public TextView mTextView1;
public ExampleViewHolder(View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.imageView);
mTextView1 = itemView.findViewById(R.id.textView);
}
}
public ExampleAdapter(ArrayList<ExampleItem> exampleList) {
mExampleList = exampleList;
}
#Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.example_item, parent, false);
ExampleViewHolder evh = new ExampleViewHolder(v);
return evh;
}
#Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
ExampleItem currentItem = mExampleList.get(position);
holder.mImageView.setImageResource(currentItem.getImageResource());
holder.mTextView1.setText(currentItem.getText1());
}
#Override
public int getItemCount() {
return mExampleList.size();
}
}
your activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.application.recyclerviewproject.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/darker_gray"
android:padding="4dp"
android:scrollbars="vertical" />
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<ExampleItem> exampleList = new ArrayList<>();
exampleList.add(new ExampleItem(R.drawable.img01, "Red"));
exampleList.add(new ExampleItem(R.drawable.img02, "Orange"));
exampleList.add(new ExampleItem(R.drawable.img03, "Yellow"));
exampleList.add(new ExampleItem(R.drawable.img04, "Green"));
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mAdapter = new ExampleAdapter(exampleList);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
}
}
Basically I am trying to code a onClickListener for a button in MainActivity.java .
This Button is defined in a resource file : main_resource.xml inside a ListView and not in activity_main.xml.
I am getting the error :
Trying to define a onClick Listener on null item.
Button btn = (Button) findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myFancyMethod(v);
}
});
Here is my main_resource.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="#+id/relativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="5dip">
<TextView
android:layout_height="wrap_content"
android:text="TextView"
android:layout_width="wrap_content"
android:id="#+id/ridedetails"
android:layout_marginLeft="2dip">
</TextView>
<EditText
android:layout_height="wrap_content"
android:hint="Quote Price"
android:layout_width="wrap_content"
android:id="#+id/PriceQuotation"
android:layout_below="#+id/ridedetails"
android:layout_marginLeft="2dip">
</EditText>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/PriceQuotation"
android:layout_marginStart="61dp"
android:layout_toEndOf="#+id/PriceQuotation"
android:text="Button" />
</RelativeLayout>
Here is my activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/myrefresh"
android:focusable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_home"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_home"
app:menu="#menu/activity_home_drawer" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".PreviousRide"
>
<ListView
android:id="#+id/incomingrides"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="30dp"
android:layout_marginTop="80dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></ListView>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
</android.support.v4.widget.SwipeRefreshLayout>
Here I am not using any Custom Adapter Class : I am injecting the data into my list view using the following ArrayAdapter code written in onRefresh() of Swipe Refresh Widget ::
final ArrayAdapter<String > adapter=new ArrayAdapter<String>(getApplicationContext(),
R.layout.home_resource, R.id.ridedetails, allNames);
l1.setAdapter(adapter);
// L1 is the listView Reference
You have to create custom class for adapter
Here is sample code for adapter.
public class MyAdapter extends ArrayAdapter<String> {
private int resourceId;
private List<String> sites = null;
private Context context;
public MyAdapter(Context context, int resource, List<String> objects) {
super(context, resource, objects);
this.context = context;
this.resourceId = resource;
this.sites = objects;
}
#Override
public String getItem(int position) {
return sites.get(position);
}
#Override
public int getCount() {
return sites.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String name = getItem(position);
View view = convertView;
if (view == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(resourceId, null);
}
TextView mTextView = (TextView) view.findViewById(R.id.ridedetails);
mTextview.setText(name);
Button mButton = (Button) view.findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, name, Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
set adapter in listview like below code.
l1.setAdapter(new MyAdapter(getApplicationContext(), R.layout.home_resource, allNames));
you should put your onClickListener in Adapter Not in Main Activity
Your Adapter
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
Button btn = (Button ) v.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myFancyMethod(v);
}
})
}
So I have an app with a listview. When you click a listview item it opens a new activity. I placed a checkbox in this new activity where when its checked, it should put a checkmark next to the listview item on the previous screen. I'm running into this error I'm guessing because I'm trying to set the checkbox from the second activity that has a different content view than the listview. I hope I explained that well.
Heres my RouteDetails.java with the checkbox code
public class RouteDetails extends AppCompatActivity {
ImageView routeImage;
String routeName;
CheckBox routeCheckBox;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_route_details);
//back button for route details view
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
///////checkbox///////////////////////////////////////////
routeCheckBox = (CheckBox) findViewById(R.id.routeCheckBox);
final ImageView checkImageView = (ImageView) findViewById(R.id.checkImageView);
routeCheckBox.setOnClickListener(new View.OnClickListener() {
public void onClick(View view)
{
if (routeCheckBox.isChecked())
{
checkImageView.setImageResource(R.drawable.birdsboroicon);
}
}
});
/////////////////////////////////////////////
//sets actionbar title
routeName = getIntent().getExtras().getString("routeName");
getSupportActionBar().setTitle(routeName);
//TextView for route details
final TextView routeDetailsView = (TextView) findViewById(R.id.routeDetailsView);
routeDetailsView.setText(getIntent().getExtras().getCharSequence("route"));
//ImageView for route details
routeImage = (ImageView) findViewById(R.id.routeImage);
final int mImageResource = getIntent().getIntExtra("imageResourceId", 0);
routeImage.setImageResource(mImageResource);
and heres the custom_row.xml that contains the imageview im trying to set based on the checkbox state.
<TextView
android:text="TextView"
android:layout_width="wrap_content"
android:layout_height="51dp"
android:id="#+id/routeText"
android:layout_weight="1"
android:textSize="18sp"
android:gravity="center_vertical"
android:textColor="#android:color/black"
android:typeface="normal"
/>
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:id="#+id/checkImageView" />
So I want the checkmark to be next to the listview item after the back button is pressed.
Ill include this other code if it is relavent
heres my RouteDetails.xml that contains the checkbox
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_route_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
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="com.example.zach.listview.RouteDetails">
<CheckBox
android:text="Route Climbed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/routeCheckBox"
android:gravity="center" />
<TextView
android:text="TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/routeDetailsView"
android:textSize="18sp"
android:textAlignment="center"
android:textColor="#android:color/black"
android:layout_below="#id/routeCheckBox"/>
<ImageView
android:layout_below="#id/routeDetailsView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/routeImage"
android:scaleType="fitCenter"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:adjustViewBounds="true" />
</RelativeLayout>
</ScrollView>
My Custom adapter.java which creates each listview row
class CustomAdapter extends ArrayAdapter<CharSequence>{
public CustomAdapter(Context context, CharSequence[] routes) {
super(context, R.layout.custom_row ,routes);
}
#NonNull
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater routeInflater = LayoutInflater.from(getContext());
View customView = convertView;
if(customView == null){customView = routeInflater.inflate(R.layout.custom_row, parent, false);}
CharSequence singleRoute = getItem(position);
TextView routeText = (TextView) customView.findViewById(R.id.routeText);
routeText.setText(singleRoute);
return customView;
}
my mainavtivity.java which is where the listview is populated
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Action Bar customization
final android.support.v7.app.ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayOptions(android.support.v7.app.ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setCustomView(R.layout.actionbar);
setContentView(R.layout.activity_main);
///// fill listview numbers I want to add
final String[] routeListviewNumbers = getResources().getStringArray(R.array.routeNumbers);
//fill list view with xml array of routes
final CharSequence[] routeListViewItems = getResources().getTextArray(R.array.routeList);
//fills route detail text view with xml array info
final CharSequence[] routeDetail= getResources().getTextArray(R.array.routeDetail);
//fills route detail image view with xml array of images
final TypedArray image = getResources().obtainTypedArray(R.array.routeImages);
//image.recycle();
//custom adapter for list view
ListAdapter routeAdapter = new CustomAdapter(this, routeListViewItems);
final ListView routeListView = (ListView) findViewById(R.id.routeListView);
routeListView.setAdapter(routeAdapter);
routeListView.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CharSequence route = routeListViewItems[position];
int imageId = (int) image.getResourceId(position, -1);
if (route.equals(routeListViewItems[position]))
{
Intent intent = new Intent(view.getContext(), RouteDetails.class);
intent.putExtra("route", routeDetail[position]);
intent.putExtra("imageResourceId", imageId);
intent.putExtra("routeName", routeListViewItems[position]);
startActivity(intent);
}
}
}
);
}
}
and my activitymain.xml which is the listview
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="0dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingTop="0dp"
tools:context="com.example.zach.listview.MainActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/routeListView"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
Edit: So I added this to my RouteDetails.java
routeCheckBox.setOnClickListener(new View.OnClickListener() {
public void onClick(View view)
{
if (routeCheckBox.isChecked())
{
//checkImageView.setImageResource(R.drawable.checkmark);
Intent check = new Intent(RouteDetails.this,CustomAdapter.class);
check.putExtra("checkImageResource", R.drawable.checkmark);
startActivity(check);
}
}
});
and this to my customAdapter.java
////////trying to set checkmark/////
ImageView checkImageView = (ImageView) customView.findViewById(R.id.checkImageView);
checkImageView.setImageResource(((Activity) getContext()).getIntent().getIntExtra("checkImageResource",0));
////////////////////////////////////////
but this is not working either. It says fatal exception unable to find explicit activity class. It's doing this I guess since CustomAdapter is not an activity, but customadapter is linked to my custom_row which contains the imageview I want to add the checkbox to. How would I do this? I'm not sure what else to try
Edit: I still haven't found a solution if anyone has any suggestions!
I've seen lots of posts regarding this question but none of them guided me through a solution to my problem. I have a listview using a custom cursoradapter which every item has a checkbox in it. This checkbox is not binded to the database, because my intention is to use it for deletion. Once delete button is clicked, all items with checkboxes checked should be deleted from view and database. I implemented the following logic, but turns out the method <my listview instance>.getCheckedItemPositions() always returns a SparseBooleanArray empty. Can anyone tell me what I am doing wrong? I am not sure if this is the best approach anyway, so any other solution or ideas are welcome.
This is my CursorAdapter
public class ExpenseCursorAdapter extends CursorAdapter {
private NumberFormat formatter = NumberFormat.getCurrencyInstance();
Context context;
private DatabaseHelper db;
public ExpenseCursorAdapter(Context context, Cursor c) {
super(context, c);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// when the view will be created for first time,
// we need to tell the adapters, how each item will look
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View retView = inflater.inflate(R.layout.expense_single_row_item, parent, false);
return retView;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// here we are setting our data
// that means, take the data from the cursor and put it in views
TextView textViewParticipantId = (TextView) view.findViewById(R.id.tv_expense_participant);
textViewParticipantId.setText(cursor.getString(cursor.getColumnIndex("name")));
TextView textViewExpenseDescription = (TextView) view.findViewById(R.id.tv_expense_description);
textViewExpenseDescription.setText(cursor.getString(cursor.getColumnIndex("description")));
TextView textViewExpenseAmount = (TextView) view.findViewById(R.id.tv_expense_amount);
textViewExpenseAmount.setText(formatter.format(Double.valueOf(cursor.getDouble(cursor.getColumnIndex("amount")))));
}
}
This is my item layout:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="1,2,3" >
<TableRow
android:id="#+id/tableRow1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="10" >
<CheckBox
android:id="#+id/cb_expense_row"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:button="#drawable/selector_check"
android:focusable="false"
android:padding="2dip"
android:weightSum="1"/>
<TextView
android:id="#+id/tv_expense_participant"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:weightSum="3"
android:gravity="left"/>
<TextView
android:id="#+id/tv_expense_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:weightSum="3"
android:gravity="left"/>
<TextView
android:id="#+id/tv_expense_amount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:weightSum="3"
android:gravity="left" />
</TableRow>
And this is the activity with the logic I am using on delete button --removeExpense():
private static final String TAG = ExpenseActivity.class.getSimpleName();
private ListView listView;
private ExpenseCursorAdapter customAdapter;
private DatabaseHelper databaseHelper;
private long eventId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_expense);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
eventId = getIntent().getLongExtra("tag_event_id", -1);
databaseHelper = new DatabaseHelper(this);
listView = (ListView) findViewById(R.id.expense_list_data);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d(TAG, "clicked on item: " + position+" - ID: "+id);
}
});
new Handler().post(new Runnable() {
#Override
public void run() {
customAdapter = new ExpenseCursorAdapter(ExpenseActivity.this, databaseHelper.getAllExpensesByEventCursor(eventId));
listView.setAdapter(customAdapter);
}
});
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
...
private void removeExpenses() {
Log.d(TAG, "Remove Expense button clicked on");
DatabaseHelper db = new DatabaseHelper(this);
SparseBooleanArray checkedItemPositions = listView.getCheckedItemPositions();
int itemCount = listView.getCount();
for (int i = itemCount - 1; i >=0; i--) {
if (checkedItemPositions.valueAt(i)) {
//db.deleteExpense(listView.getItemIdAtPosition(checkedItemPositions.keyAt(i)));
db.deleteExpense(listView.getItemIdAtPosition(i));
}
customAdapter.notifyDataSetChanged();
}
checkedItemPositions.clear();
listView.setAdapter(customAdapter);
listView.clearChoices();
if (db != null){
db.close();
}
}
I've working on ListView with a custom BaseAdapter which I've watched on the Slidenerd tutorial series here:(It's not important to watch to understand my question)
http://www.youtube.com/watch?v=_l9e2t4fcfM&list=PLonJJ3BVjZW6hYgvtkaWvwAVvOFB7fkLa&index=91
After running the code on the virtual device there is no error but not ListView too.
Is it possible to tell me what's the problem of my code?
public class List extends Activity {
ListView lv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
lv = (ListView) findViewById(R.id.listView);
lv.setAdapter(new EhsanAdapter(this));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.list, menu);
return true;
}
}
class SingleRow{
String title;
String description;
int image;
public SingleRow(String title,String description,int image) {
this.title = title;
this.description=description;
this.image=image;
}
}
class EhsanAdapter extends BaseAdapter{
ArrayList<SingleRow> list;
Context context;
public EhsanAdapter(Context c) {
list = new ArrayList<SingleRow>();
context = c;
Resources res = c.getResources();
String[] titles = res.getStringArray(R.array.titles);
String[] descriptions = res.getStringArray(R.array.descriptions);
int[] images = {R.drawable.image1,R.drawable.image2,R.drawable.image3,R.drawable.image4,R.drawable.image5};
for(int i=0;i<10;i++){
list.add(new SingleRow(titles[i], descriptions[i], images[i]));
}
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int i) {
return list.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.single_row, viewGroup,false);
TextView title = (TextView) row.findViewById(R.id.txtTitle);
TextView description = (TextView) row.findViewById(R.id.txtDescription);
ImageView image = (ImageView) row.findViewById(R.id.imgPic);
SingleRow temp = list.get(i);
title.setText(temp.title);
description.setText(temp.description);
image.setImageResource(temp.image);
return row;
}
}
The layout of activity:
<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=".List" >
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listView"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
</RelativeLayout>
The layout of single row:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:layout_margin="10dp"
android:id="#+id/imgPic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/image1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Title"
android:id="#+id/txtTitle"
android:layout_alignTop="#+id/imgPic"
android:layout_toRightOf="#+id/imgPic"
android:layout_alignParentRight="true">
</TextView>
<TextView
android:id="#+id/txtDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/imgPic"
android:layout_marginLeft="25dp"
android:layout_toRightOf="#+id/imgPic"
android:layout_marginTop="20dp"
android:text="Description"
android:ems="10">
</TextView>
</RelativeLayout>
Remove the line LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); from getView() method and instead add it in the constructor of EhsanAdapter class.
I see different issues:
The layout of single row contains a relative layout which the android:layout_height="match_parent" should be android:layout_height="wrap_content"
Then inside the Adapter you are neither recycling the views nor using the ViewHolder pattern:
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
About ViewHolder pattern implementation optimisation in ListView
http://www.jmanzano.es/blog/?p=166
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null){ //The row view is not created, let's do it:
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.single_row, viewGroup,false);
TextView title = (TextView) row.findViewById(R.id.txtTitle);
TextView description = (TextView) row.findViewById(R.id.txtDescription);
ImageView image = (ImageView) row.findViewById(R.id.imgPic);
// Here we add the title, description and image inside the ViewHolder
....
}else{
//With the View holder pattern we get the views inside the row view to fill it later
....
}
// Now we get the SingleRow and we fill it using the ViewHolder pattern
SingleRow temp = list.get(i);
....
return row;
}
You only have 5 images and you wrote i<10 you should've wrote i<5 the amount of "titles" and "descriptions" and "images" must be the same.
for(int i=0;i<5;i++){
list.add(new SingleRow(titles[i], descriptions[i], images[i]));
}