Trying to teach myself how to do these things. I'm trying to figure out how to dynamically add an image to a ListView item. What I'm doing is pulling JSON data in that returns the following:
{"mdslist":
[
{
"UID":"3",
"name":"Stamford, CT",
"date":"March 10, 2018",
"icon":"badge_stamford"
},
{
"UID":"4",
"name":"Enschede, The Netherlands",
"date":"March 11, 2018",
"icon":"badge_enschede"
}
]
}
That data is then processed and dumped into a ListView. The ListView has individual containers to hold the data - note the temporary img in the ImageView tag:
md_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/md_item_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:minHeight="65dp">
<ImageView
android:id="#+id/md_icon"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
android:contentDescription="#string/md_logo"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/badge_stamford" />
<TextView
android:id="#+id/md_name"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:paddingBottom="2dip"
android:paddingTop="6dip"
android:textColor="#android:color/black"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/md_icon"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/md_date"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginBottom="4dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:paddingBottom="2dip"
android:textColor="#color/dark_gray"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/md_icon"
app:layout_constraintTop_toBottomOf="#+id/md_name" />
</android.support.constraint.ConstraintLayout>
The JSON data gets injected during an onPostExecute() call after getting processed:
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (pd.isShowing()) {
pd.dismiss();
}
/**
* Dump parsed JSON data into ListView
**/
ListAdapter adapter = new SimpleAdapter(
md_list_all.this, mdList,
R.layout.md_list_item, new String[]{"name", "date"}, new int[]{R.id.md_name, R.id.md_date});
lv.setAdapter(adapter);
}
As you can see, I have no facility to add the icon data. Those files are named as the JSON data, with a .jpg extension. What I'd like is to grab the JSON 'icon' info, and inject it into the ImageView.
As Rizwan said in the comments you probably want to use a URL to load the image from a server.
To answer the other part of your question you need to create a custom ListAdapter, SimpleAdapter won't give you much flexibility.
Below I took some code I did in the past and tried to make it easy enough to understand, let me know if you have any questions on it?
class AdvancedAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mLayoutInflater;
private ArrayList<CustomData> mItems;
AdvancedAdapter(Context context, ArrayList<CustomData> items) {
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mContext = context;
mItems = items;
}
#Override
public int getCount() {
return mItems.size();
}
#Override
public Object getItem(int i) {
return mItems.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
convertView = layoutInflater.inflate(R.layout.layout_for_list_item, null);
}
TextView titleView = (TextView) convertView.findViewById(R.id.title);
final ImageView imageView = (ImageView) convertView.findViewById(R.id.image);
titleView.setText(mItems.get(position).name());
imageView.setImageResource(0); //Nulls out the image while loading
......
...... Load image from URL
imageView.setImageBitmap((Bitmap) finalImage);
.....
return convertView;
}
}
Related
I have a ListView that shows list items (duh). When you click on a list item, another Activity opens. Part of the list item layout is a grey star, an ImageView. When you click on this ImageView, I don't want to open another Activity, but I want to change the color of the star to green (= mark the item as favourite) or back (= mark it as not favourite). I managed to do that with an OnClickListener, loading another ImageView on Click, and refreshing the adapter. But for the ImageView to change, after clicking it I need to leave the Activity and enter again. It doesn't refresh instantly. Why, and how can I change that? I've tried lots of different versions, so far nothing works. My ListViewAdapter extends BaseAdapter. Thank you!
public class ListViewAdapterKeysAToZ extends BaseAdapter {
private ArrayList<KeyTagIntern> keyTags;
private ObservableArrayList<KeyTagIntern> list;
private Context context;
TextView name;
TextView place;
ImageView star, favoriteStar;
public ListViewAdapterKeysAToZ(Context context, ObservableArrayList<KeyTagIntern> list)
{
this.context = context;
this.list = list;
keyTags = new ArrayList<>();
for (KeyTagIntern keytag : list) {
keyTags.add(keytag);
}
//(....)
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
KeyTagIntern key = (KeyTagIntern) getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item_keys, parent, false);
}
name = (TextView) convertView.findViewById(R.id.text_keylist_item);
name.setText(key.getName());
place = (TextView) convertView.findViewById(R.id.text_keylist_item_place);
place.setText(key.getPlace());
star = (ImageView) convertView.findViewById(R.id.right_icon_keylist_item);
favoriteStar = (ImageView) convertView.findViewById(R.id.right_icon_keylist_item_favorite);
if (key.isFavorite())
{
star.setVisibility(View.INVISIBLE);
favoriteStar.setVisibility(View.VISIBLE)
favoriteStar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// This makes key.isFavourite() = false for the next time
Paper.book().delete(FAVORIT + String.valueOf(key.getKeyTagID()));
//Since notifyDataSetChanged() didn't work for me, I tried this - but no change
int index = list.indexOf(key);
list.remove(index);
list.add(index, key);
keyTags = new ArrayList<>();
for (KeyTagIntern keytag : list) {
keyTags.add(keytag);
}
notifyDataSetChanged();
}
});
}
// Then do the opposite for if (!key.isFavourite())
Und hier das 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:id="#+id/list_item_keys"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#color/MiddleDarkGrey">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/btn_list_item_keys"
android:layout_width="match_parent"
android:layout_height="#dimen/height_list_item"
android:layout_marginBottom="3dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="3dp"
android:background="#drawable/white_list_item"
android:paddingLeft="13dp"
android:paddingRight="10dp">
<ImageView
android:id="#+id/icon_keylist_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:visibility="visible"
app:srcCompat="#drawable/ic_key" />
<ImageView
android:id="#+id/icon_reserved"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/chb_add_key"
android:layout_centerVertical="true"
android:visibility="invisible"
app:srcCompat="#drawable/ic_reservate_orange" />
<ImageView
android:id="#+id/icon_taken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/chb_add_key"
android:layout_centerVertical="true"
android:visibility="invisible"
app:srcCompat="#drawable/ic_taken_red" />
<TextView
android:id="#+id/text_keylist_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_toEndOf="#+id/icon_keylist_item"
android:layout_toRightOf="#+id/icon_keylist_item"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:text="Text"
android:textColor="#color/DarkGrey"
android:textSize="#dimen/text_list_item" />
<TextView
android:id="#+id/text_keylist_item_place"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/text_keylist_item"
android:layout_alignLeft="#+id/text_keylist_item"
android:layout_marginLeft="2dp"
android:layout_marginBottom="5dp"
android:text="Where is the key?"
android:textColor="#color/DarkGrey"
android:textSize="#dimen/text_list_item_sub" />
<ImageView
android:id="#+id/right_icon_keylist_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
app:srcCompat="#drawable/ic_fav_green" />
<ImageView
android:id="#+id/right_icon_keylist_item_favorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/ic_fav_chosen"
android:visibility="invisible"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
I think your approach should be something like this.
rather hiding and displaying an image just change source of it!
if (key.isFavorite())
{
favoriteStar.setImageResource(R.drawable.aaa);
favoriteStar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
favoriteStar.setImageResource(R.drawable.bbb);
// and vice-versa
and I don't thing you will be needing notifyDataSetChanged(); as you are making no changes in the Listdata actually!
In the end the answer was rather stupid, as it is so often, and you guys couldn't have helped me since I excluded the code at the beginning of my adapter class (added it now). It actually worked the whole time, but I didn't see it, since the listitem at the very end of the list was changed, not the selected one. This was due to me declaring the variables at the beginning of the adapter class, rather than inside the getView method.
I changed it to this and now it works perfectly:
public class ListViewAdapterKeysAToZ extends BaseAdapter {
private ArrayList<KeyTagIntern> keyTags;
private ObservableArrayList<KeyTagIntern> list;
private Context context;
public ListViewAdapterKeysAToZ(Context context, ObservableArrayList<KeyTagIntern> list) {
this.context = context;
this.list = list;
keyTags = new ArrayList<>();
for (KeyTagIntern keytag : list) {
keyTags.add(keytag);
}
// (...)
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
KeyTagIntern key = (KeyTagIntern) getItem(position);
TextView name;
TextView place;
ImageView star, favoriteStar;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item_keys, parent, false);
}
name = (TextView) convertView.findViewById(R.id.text_keylist_item);
name.setText(key.getName());
place = (TextView) convertView.findViewById(R.id.text_keylist_item_place);
place.setText(key.getPlace());
star = (ImageView) convertView.findViewById(R.id.right_icon_keylist_item);
favoriteStar = (ImageView) convertView.findViewById(R.id.right_icon_keylist_item_favorite);
if (key.isFavorite()) {
star.setVisibility(View.INVISIBLE);
favoriteStar.setVisibility(View.VISIBLE);
}else {
star.setVisibility(View.VISIBLE);
favoriteStar.setVisibility(View.INVISIBLE);
}
star.setOnClickListener(v -> {
key.setFavorite(true);
Paper.book().write(FAVORIT + String.valueOf(key.getKeyTagID()), true);
notifyDataSetChanged();
});
favoriteStar.setOnClickListener(v -> {
key.setFavorite(false);
Paper.book().delete(FAVORIT + String.valueOf(key.getKeyTagID()));
notifyDataSetChanged();
});
I am using the listView widget on android, and in preview list content I chose "checked list" item
Basically it is a list of items and I should be able to check some items and when I do the check mark next to the item becomes visible (it isn't a checkbox, that is the difference between many other checkable lists)
I don't know how to use it, I would like to know at least how I can check some item, that is make the check mark visible, because when I click on an item, it is clickable but nothing happens...
image of listview in simulator
image of listview in editor
here is my xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:rsb="http://schemas.android.com/apk/res-auto"
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"
android:background="#fffefdff">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="540dp"
android:weightSum="1"
android:id="#+id/linearLayoutPreferences"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:focusableInTouchMode="false"
android:divider="#ff080808"
android:dividerPadding="#dimen/activity_horizontal_margin"
android:showDividers="middle|beginning|end">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/listView"
tools:listitem="#android:layout/simple_list_item_checked"
android:clickable="true"
android:fastScrollAlwaysVisible="false"
android:choiceMode="multipleChoice"
android:contextClickable="false" />
</LinearLayout>
here is my java file
public class Popneighbourhood extends AppCompatActivity {
ListView listNeighbourhood;
String[] neighbourhood = new String[]{
"Alamo Square/NOPA", "Castro/Upper Market", "Central Richmond", "Cole Valley/Ashbury Heights", "Downtown/Civic/Van Ness", "Duboce Triangle",
"Financial District", "Glen Park", "Haight Ashbury", "Hayes Vallez", "Ingleside/SFSU/CCSF", "Inner Richmond",
"Inner Sunset/UCSF", "Jordan Park/Laurel Heights", "Laurel Heights/Presidio", "Lower Haight", "Lower Nob Hill", "Lower Pac Heights",
"Marina/Cow Hollow", "Mission Bay", "Mission District", "Nob Hill", "Noe Valley", "North Beach/Telegraph Hill",
"Oakland North/Temescal", "Pacific Heights"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popneighbourhood);
ActionBar actionBar=getSupportActionBar();
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setIcon(R.mipmap.logofrontdoor);
listNeighbourhood = (ListView) findViewById(R.id.listView);
//android.R.layout.simple_list_item_1 est une vue disponible de base dans le SDK android,
//Contenant une TextView avec comme identifiant "#android:id/text1"
ArrayAdapter<String> adapter = new ArrayAdapter<String>(Popneighbourhood.this,
android.R.layout.simple_list_item_1, neighbourhood);
listNeighbourhood.setAdapter(adapter);
//adapter code , i just took one of the adapter source from my project, notice the imageView, iv_item_fragment_dashboard_country_list_select, is toggled when you select.
public class DashboardCountryListAdapter extends BaseAdapter {
private Context mContext;
private List<Country> mCountryList = new ArrayList<>();
public DashboardCountryListAdapter(Context context, List<Country> countryList) {
mContext = context;
mCountryList = countryList;
}
#Override
public int getCount() {
return mCountryList.size();
}
#Override
public Object getItem(int position) {
return mCountryList.isEmpty() ? null : mCountryList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.fragment_dashboard_country_list, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if (!mCountryList.isEmpty()) {
Country country = mCountryList.get(position);
int image = country.getImage();
if (image != -1) {
viewHolder.iv_item_fragment_dashboard_country_list.setImageResource(image);
if (country.getSelected()){
viewHolder.iv_item_fragment_dashboard_country_list_select.setVisibility(View.VISIBLE);
}
else
viewHolder.iv_item_fragment_dashboard_country_list_select.setVisibility(View.GONE);
}
viewHolder.tv_item_fragment_dashboard_country_list.setText(country.getName());
}
return convertView;
}
class ViewHolder {
#Bind(R.id.iv_item_fragment_dashboard_country_list)
ImageView iv_item_fragment_dashboard_country_list;
#Bind(R.id.tv_item_fragment_dashboard_country_list)
TextView tv_item_fragment_dashboard_country_list;
#Bind(R.id.iv_item_fragment_dashboard_country_list_select)
ImageView iv_item_fragment_dashboard_country_list_select;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
public void updateList(List<Country> list) {
mCountryList = list;
notifyDataSetChanged();
}
}
//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="50dp">
<ImageView
android:id="#+id/iv_item_fragment_dashboard_country_list"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:adjustViewBounds="true"
android:layout_width="20dp"
android:layout_height="15dp" />
<com.UTU.View.UtuTextView
android:id="#+id/tv_item_fragment_dashboard_country_list"
android:textColor="#color/chic_black"
android:textSize="18sp"
android:gravity="center_vertical"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<ImageView
android:id="#+id/iv_item_fragment_dashboard_country_list_select"
android:src="#drawable/icon_check_teal"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:adjustViewBounds="true"
android:layout_width="13dp"
android:layout_height="10dp" />
</LinearLayout>
I can tell you why the editor looks different from the running app:
In your layout XML the list view has this attribute:
tools:listitem="#android:layout/simple_list_item_checked"
but in your code you have
ArrayAdapter<String> adapter = new ArrayAdapter<String>(Popneighbourhood.this,
android.R.layout.simple_list_item_1, neighbourhood);
so you're using an entirely different layout for the list item.
You need to put R.layout.simple_list_item_checked in the adapter constructor, and you will probably need to change to the constructor that specifies the id of the TextView to use.
I have a ListView in one of my activities that I have bound to an ArrayList using a custom ArrayAdapter. I have set an OnItemClickListener to the ListView which should call a method that starts another activity. However, I find that when I click on the ListView items, it only sometimes works. Sometimes it will start the activity as it should; other times it seems to detect the click (the ripple effect appears on the list item) but does nothing; other times it doesn't even appear to detect the click (the ripple effect doesn't appear).
I've tried all the usual suggestions that I've come across: blocking descendants on the parent view item, setting clickable and focusable to false on all the components of the item views, setting isEnabled to return true in the custom adapter, etc, but the behavior remains the same. Any help appreciated. Here is the relevant code:
Activity containing the ListView:
public class ViewCollectionActivity extends AppCompatActivity {
private final String className = this.getClass().getSimpleName();
private CollectionHandler collectionHandler;
private Context context;
private ArrayList<Game> displayedCollection;
private GameCollectionAdapter collectionAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_collection);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
context = this;
collectionHandler = CollectionHandler.getInstance(this);
TextView view = null;
if (collectionHandler.getDisplayedCollection().size() > 0) {
view = (TextView) findViewById(R.id.no_items_textview);
view.setVisibility(View.GONE);
}
String currentDate = collectionHandler.getDateLastSynchronised();
view = (TextView) findViewById(R.id.last_updated_textview);
view.setText("Last synchronised: " + currentDate + " Total games: " + String.valueOf(collectionHandler.getDisplayedCollection().size()));
collectionAdapter = collectionHandler.getCollectionAdapter();
ListView listView = (ListView) findViewById(R.id.collection_list_view);
listView.setAdapter(collectionAdapter);
AdapterView.OnItemClickListener collectionItemClickListener = new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
launchGameDetailsActivity(position);
}
};
listView.setOnItemClickListener(collectionItemClickListener);
}
public void launchGameDetailsActivity(int position){
Log.d(className,"Starting lauchGameDetailsActivity method");
collectionHandler.setSelectedGame(position);
Intent intent = new Intent(this,ViewGameDetailsActivity.class);
startActivity(intent);
Log.d(className, "Ending lauchGameDetailsActivity method");
}
The XML for the activity:
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
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.bleachedlizard.ludome.viewcollection.ViewCollectionActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Synchronise Collection"
android:onClick="synchroniseCollection"/>
<TextView
android:id="#+id/last_updated_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Last synchronised: "
android:textAlignment="center"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Display Collection"
android:visibility="gone"
android:onClick="displayCollection"/>
<ListView
android:id="#+id/collection_list_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
<TextView
android:id="#+id/no_items_textview"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="You have no items in your collection."
android:textAlignment="center"
android:textSize="20sp"/>
</LinearLayout>
The XML for the item views:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/collection_item_layout"
android:layout_width="match_parent"
android:layout_height="75dp"
android:orientation="horizontal"
android:clickable="false"
android:descendantFocusability="blocksDescendants"
android:focusable="false"
android:focusableInTouchMode="false">
<ImageView
android:id="#+id/collection_item_image"
android:layout_width="75dp"
android:layout_height="75dp"
android:src="#drawable/testimage"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
/>
<TextView
android:id="#+id/collection_item_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:padding="16dp"
android:singleLine="false"
android:textColor="#android:color/darker_gray"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:textIsSelectable="false"/>
<TextView
android:id="#+id/collection_item_plays"
android:layout_width="100dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:padding="8dp"
android:textColor="#android:color/darker_gray"
android:text="Plays: 0"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:textIsSelectable="false"/>
</LinearLayout>
The code for the custom adapter:
public class GameCollectionAdapter extends ArrayAdapter<Game> {
private ArrayList<Game> collection;
public GameCollectionAdapter(Context context, int resource, ArrayList<Game> collection){
super(context, resource, collection);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout gameView = (LinearLayout) convertView;
LayoutInflater mInflater = LayoutInflater.from(getContext());
if (gameView == null) {
gameView = (LinearLayout) mInflater.inflate(R.layout.collection_item_view, null);
}
//Game game = collection.get(position);
Game game = super.getItem(position);
if (game != null) {
// This is how you obtain a reference to the TextViews.
// These TextViews are created in the XML files we defined.
TextView gameTitle = (TextView) gameView.findViewById(R.id.collection_item_name);
TextView numOfPlays = (TextView) gameView.findViewById(R.id.collection_item_plays);
ImageView thumbnail = (ImageView) gameView.findViewById(R.id.collection_item_image);
// check to see if each individual textview is null.
// if not, assign some text!
if (gameTitle != null){
gameTitle.setText(game.getTitle());
}
if (numOfPlays != null){
numOfPlays.setText("Plays: " + String.valueOf(game.getNumOfPlays()));
}
if (thumbnail != null){
thumbnail.setImageBitmap(game.getThumbnail());
}
}
// the view must be returned to our activity
return gameView;
}
#Override
public boolean isEnabled(int position) {
return true;
}
}
I discovered what was causing the problem: the way I had set up the array that backed the ListView meant that it was downloading and storing the Bitmaps for every element in the array all the time. Once I changed the implementation so that it only downloaded the images as the ListView required them, then that seemed to improve performance and the onClickListener started to work fine.
The implementation I used was the exact same one shown here:
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
I think the issue is due to the position of the item selection whenever you click you have an list position which is passed to your method launchGameDetailActivity(int position) check with log or toast on item click what all the position you are getting do the needful.
Here is my code try this like this if it helps.
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(RecipeClass.this, "Position is" + position, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(RecipeClass.this, RecipeIngredients.class)
intent.putExtra("position", position);
startActivity(intent);
}
Check your arraylist value also whether they are not null.
So I've searched around for an answer or a possible solution to this problem for a couple weeks now and still haven't gotten any farther. I'm working on building an app that rewards users with points after certain things. One of the pages they can visit is a leader board based off of the friends the user has.
I'm able to implement the leader board and print the users in order based off of their points, but can't implement a bar graph style look. Like So: http://imgur.com/tF51RsA
(Had to post a link because I can't paste a picture in here)
Here is what I've tried so far:
1. Adding a to xml and trying to getLayoutParams in the custom adapter then set the width, which didn't work.
2. using onDraw to draw a rectangle over top of the list item.
Here is my Leader board xml file (or close to it):
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#+id/leader_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left|top"
android:background="#00000000">
</LinearLayout>
My listview row xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="#+id/bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/user_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_centerVertical="true"
android:background="#drawable/ic_default_user"/>
<TextView
android:id="#+id/rank"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="10dp"
android:layout_toRightOf="#+id/user_image"/>
<TextView
android:id="#+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="20dp"
android:textSize="16sp"
android:layout_toRightOf="#+id/rank"/>
<TextView
android:id="#+id/score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/user_name"
android:gravity="right"
android:paddingRight="15dp"/>
</RelativeLayout>
</FrameLayout>
and my custom ArrayAdapter in my leaderboard class
public class LeaderAdapter extends ArrayAdapter<LeaderboardDM>{
ArrayList<LeaderboardDM> leaders;
int layoutResourceId;
public LeaderAdapter(Context context, int layoutResourceId, ArrayList<LeaderboardDM> leaders){
super(context, layoutResourceId, leaders);
this.leaders = new ArrayList<LeaderboardDM>();
this.leaders = leaders;
this.layoutResourceId = layoutResourceId;
}
public View getView(int position, View convertView, ViewGroup parent){
View v = convertView;
ViewHolder viewHolder = null;
if(v == null){
v = getLayoutInflater().inflate(layoutResourceId, null, false);
viewHolder = new ViewHolder();
viewHolder.userImage = (ImageView) v.findViewById(R.id.user_image);
viewHolder.rank = (TextView) v.findViewById(R.id.rank);
viewHolder.userName = (TextView) v.findViewById(R.id.user_name);
viewHolder.score = (TextView) v.findViewById(R.id.score);
v.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) v.getTag();
}
LeaderboardDM lead = leaders.get(position);
if(lead != null){
//doesn't set user image yet
viewHolder.userName.setText(lead.user);
viewHolder.score.setText(String.valueOf(lead.points));
viewHolder.rank.setText("#"+String.valueOf(position+1));
}
return v;
}
class ViewHolder{
ImageView userImage;
TextView rank, userName, score;
}
}
and the leaderboardDM class
public class LeaderboardDM{
public String user;
public int points;
public String profilePicUrl;
public void setUserName(String user){
this.user = user;
}
public String getUserName(){
return user;
}
public void setPoints(int points){
this.points = points;
}
public int getPoints(){
return points;
}
public void setProfilePic(String url){
this.profilePicUrl = url;
}
public String getProfilePicUrl(){
return profilePicUrl;
}
}
The list gets sorted through using a comparator and again prints in order of their score. If anyone has an idea on how to create something like this please help point me in the right direction.
Thanks!
Edit:
Thanks to #Ridcully I was able to solve this issue.
The solution worked perfectly for anyone in the future that may do this, was to create a custom progress bar and get the drawable from the resources then set the ProgressDrawable to that drawable. From there I would set the width by setProgress(int width).
You could use a RelativeLayout and put a ProgressBar (with customized drawable) in the back. This way you can set the width of the bar by a simple setProgress().
Edit: Ok, i took the advice given in the answers and the difference is huge! I've replaced my SeriesAdapter in the post with the new one.
For one a know make the calculations with in the sql query (to know
total number of episodes and totalt numer of watched episodes). I also
store the bitmap in a hashmap once it has been loaded so that it don't
have to load twice, I'm looking in to some other solution as I'm
afraid of OutOfMemoryException.
I am new to android and i want to display an listview with images that i have stored on the external storage.
The images are downloaded earlier and are now as I said stored in the external storage, here is an example of the images http://thetvdb.com/banners/graphical/80348-g32.jpg and I compress the images to 80% when saving them to save some space.
I have tried several methods to make the listview scroll smooth but I'm clearly in over my head here. I have provided my layout for the list items and my adapter in case I do something strange here.
I would appreciate any tips and tricks that would improve my listview.
SeriesAdapter:
public static class SeriesAdapter extends ArrayAdapter<Series> {
static class viewHolder
{
ImageView image;
TextView information;
String seriesId;
String season;
ProgressBar progress;
TextView txtSmallView;
}
private final Context context;
private final ArrayList<Series> series;
private DateHelper dateHelper;
private final DatabaseHandler db;
Object mActionMode;
int resource;
public SeriesAdapter(Context context, int resource, ListView lv, ArrayList<ExtendedSeries> objects)
{
super(context, resource, objects);
this.context = context;
this.series = objects;
this.resource = resource;
db = new DatabaseHandler(context);
dateHelper = new DateHelper();
cache = new HashMap<String, Bitmap>();
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
viewHolder holder;
ExtendedSeries s = series.get(position);
if(convertView == null)
{
convertView = View.inflate(context, resource, null);
holder = new viewHolder();
holder.image = (ImageView)convertView.findViewById(R.id.imgSeriesImage);
holder.information = (TextView)convertView.findViewById(R.id.txtUpcomingEpisode);
holder.progress = (ProgressBar)convertView.findViewById(R.id.pgrWatched);
convertView.setTag(holder);
}
else
{
holder = (viewHolder)convertView.getTag();
}
if(s != null)
{
holder.seriesId = s.getImage();
convertView.setTag(R.string.homeactivity_tag_id,s.getID());
convertView.setTag(R.string.homeactivity_tag_seriesid,s.getSeriesId());
holder.progress.setMax(s.getTotalEpisodes());
holder.progress.setProgress(s.getWatchedEpisodes());
holder.image.setImageBitmap(getBitmapFromCache(s.getImage()));
holder.information.setText(s.getNextEpisodeInformation().equals("") ? context.getText(R.string.message_show_ended) : s.getNextEpisodeInformation());
}
return convertView;
}
Listitem layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="#+id/imgSeriesImage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:focusable="false"
android:scaleType="centerCrop"
android:src="#drawable/noimage" />
<RelativeLayout
android:id="#+id/relProgressView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:orientation="vertical" >
<ProgressBar
android:id="#+id/pgrWatched"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="21dp"
android:max="100"
android:progress="50"
android:progressDrawable="#drawable/progressbar" />
<TextView
android:id="#+id/txtUpcomingEpisode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:padding="3dp"
android:scrollHorizontally="true"
android:scrollbars="none"
android:shadowColor="#android:color/black"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="1"
android:textAllCaps="true"
android:textColor="#ffffffff"
android:textSize="11sp"
android:textStyle="normal|bold"
android:typeface="normal" />
</RelativeLayout>
Activity layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ListView
android:id="#+id/lstMySeries"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:longClickable="true"
android:divider="#000000"
/>
The getView method needs to be as light as possible as this is called for every item in the row when it is shown onscreen.
You already implement the viewHolder pattern which is good, but you also need to preprocess your "watched episode" logic so you are not looping and counting in the display code. You also need to do the db.GetAiredEpisodes call outside of this method call.
I dont know why your code are doing an IO operation in the getView() method . this is an expensive operation ,can't you make it a field in the DB ??? can't you calcaulated else where ??? perhaps in the data loader i.e where you load the series ,.