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 ,.
Related
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;
}
}
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();
});
UPDATE WITH CODE (Sorry for crappy formatting of my code, some reason it had problems allowing me to post it so I had to mess with the lines for a whole to get it to allow me to save thisedit)
Here is the idea. I have an app that works with Clarifia's image recognition. I generated the app using Google's pre built navegation bar, so there is extra xml files and code for that, but it can be ignored the two needed for this is activity_main.xml and content_main.xml. anyways in content_main.xml it is a linear layout that has an imageview and a listview. My goal is to dynamically generate the listview with a list of BUTTONS. each button will have setText() done to it to give it a tag, so for example if a image selected is a dog, and the tags are dog, animal, etc, then that many buttons will be generated, with a setText() of one button being dog, the other button being animal, etc . now Since I have to do a network call, the network call is done in asynctask. After it is done, the method onPostExecute() is called and from there I get the tags. NOW since i got the tags, I want to call set an adapter that will hold an array of buttons, and loop geting the ID for each button and doing settext() on each button with the tags. from there i want to set the adapter to the list view..
Problems:
way to many to count, but I THINK i narrowed it down to me not knowing how to get the "views" from the second xml file to have the elements be used on the first xml file, because everything comes out NULL. I tried googling it but i just keep running into road blocks. I just want to name each button with a tag and put them into listview, but like i said, since these elements are in a different xml file than main_activity, I think this is the problem. so here is the code per request.
MainActivity.java
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener
{
private static final String CLASS = MainActivity.class.getSimpleName();
private Button selectButton;
private Toolbar toolbar;
private NavigationView navigationView;
private Clari
faiData cdata = null;
private ImageView imageview;
private ListView listview;
private TagAdapter adapter;
private List<Button> data;
protected Context context;
private GoogleApiClient client;
protected LinearLayout main;
#Override
protected void onCreate(Bundle savedInstanceState)
{
// THIS IS MY ATTEMPT TO DO THIS
// http://www.java2s.com/Code/Android/UI/UsingtwolayoutxmlfileforoneActivity.htm
super.onCreate(savedInstanceState);
context = MainActivity.this;
main = new LinearLayout (this);
setContentView(R.layout.activity_main);
// AUTO GENERATED stuff left out for nav bar, just showing this line*********
selectButton = (Button) findViewById(R.id.select_button);
selectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Intent media_intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// START API OVER NET
startActivityForResult(media_intent, cdata.getOKCode());
}
});
// MY STUFF********************************************************
cdata = new ClarifaiData(this);
imageview = (ImageView) findViewById(R.id.image_view);
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == cdata.getOKCode() && resultCode == RESULT_OK)
{
Uri image = intent.getData();
if (image != null) {
// LEFT OUT STUFF FOR IMAGE RESIZING***************************
//************************************************** START LOOKING HERE***************************************
new AsyncTask<Uri, Void, RecognitionResult>()
{
#Override
protected RecognitionResult doInBackground(Uri... image)
{
// SO API CALL OVER INTERNET, SO NEEDED ASYNC
return cdata.recognizeBitmap(image[0]);
}
#Override
protected void onPostExecute(RecognitionResult result)
{
super.onPostExecute(result);
if (cdata.getTags(result))
{
selectButton.setEnabled(true);
selectButton.setText("Select a photo");
// MY ATTEMPT TO GET THE
// http://www.java2s.com/Code/Android/UI/UsingtwolayoutxmlfileforoneActivity.htm
LayoutInflater inflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout taglayout = (LinearLayout) inflate.inflate(R.layout.tag_list_item_trio_item, null);
LinearLayout.LayoutParams parm = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
listview = (ListView) main.findViewById(R.id.tagview);
main.addView(taglayout, parm);
// this is a arraylist of tags that hold strings
List tags = cdata.getMapTags();
// data is a array of buttons, each button will be labled by each value in tags
data = new ArrayList<Button>();
for (int i = 0; i < tags.size(); i++)
{
// GET ID FOR EACH BUTTON AND PUT IT INTO ARRAY THEN SETTEXT
String loc = "button_item_" + i;
int ID = getResources().getIdentifier(loc, "id", getPackageName());
Button temp = (Button) main.findViewById(R.id.button_item_0);
temp.setText("TEST " + i);
}
// HERE IS THE PROBLEM, I NEED A WAY TO GET THE LAYOUT STUFF FROM MAIN ACTIVITY
adapter = new TagAdapter(MainActivity.this, getResources().getIdentifier("tag_list_item_trio_item", "id", getPackageName()), data);
listview.setAdapter(adapter);
}
else
bottomToast(cdata.getRecError());
}
}.execute(image);
} else {
bottomToast(cdata.getLoadError());
}
}
}
tagAdapter.java
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class TagAdapter extends ArrayAdapter<Button> {
private Context context;
private List<Button> taglist;
public TagAdapter(Context context, int resource, List<Button> objects) {
super(context, resource, objects);
Log.i("Test", "constructor " );
this.context = context;
this.taglist = objects;
}
#Override
public int getCount()
{
return taglist.size();
}
getView(int, android.view.View, android.view.ViewGroup)
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.tag_list_item_dual_item, parent, false);
final Button tag = taglist.get(position);
View view = null;
view = layoutInflater.inflate(R.layout.tag_list_item_trio_item, parent, false);
else
{
view = layoutInflater.inflate(R.layout.tag_list_item_dual_item, parent, false);
Button nameTextView = (Button) view.findViewById(R.id.first_button_dual_item);
nameTextView.setText("test");
Button nameTextView2 = (Button) view.findViewById(R.id.second_button_dual_item);
nameTextView2.setText("test2");
}
return view;
}
}
content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content"
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"
android:gravity="center|bottom"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:adjustViewBounds="true"
android:id="#+id/image_view"
android:background="#653fff"
android:layout_weight="0.5"
android:padding="1dp" />
<ListView
android:id="#+id/tagview"
android:layout_width="match_parent"
android:layout_weight="0.35"
android:layout_height="0dp"
android:padding="5dp"
android:background="#68343f"
android:layout_marginTop="10dp"
android:layout_gravity="center_horizontal"
android:textAlignment="center" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:layout_gravity="center_horizontal"
android:textAlignment="center"
/>
<Button
android:id="#+id/select_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/sel_image"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:background="#3d88ec" />
</LinearLayout>
tag_list_item_trio.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_centerHorizontal="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:layout_centerInParent="true"
android:orientation="horizontal">
<Button
android:id="#+id/button_item_0"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 1"
android:textColor="#ffffff"
/>
<Button
android:id="#+id/button_item_1"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 2"
android:textColor="#ffffff"
/>
<Button
android:id="#+id/button_item_2"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 3"
android:textColor="#ffffff"
/>
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_centerHorizontal="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:layout_centerInParent="true"
android:orientation="horizontal">
<Button
android:id="#+id/button_item_0"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 1"
android:textColor="#ffffff"
/>
<Button
android:id="#+id/button_item_1"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 2"
android:textColor="#ffffff"
/>
<Button
android:id="#+id/button_item_2"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 3"
android:textColor="#ffffff"
/>
</LinearLayout>
One thing you should know is a Listview and its items are virtualized or recycled/reused or duplicated if i should say. so from how i see it i think your approach is off.
This is how i suggest you rectify it, before i get to that i want to clarify the way i understood a portion of your requirement
My goal is to dynamically generate the listview with a list of BUTTONS. each button will have setText() done to it to give it a tag, so for example if a image selected is a dog, and the tags are dog, animal, etc, then that many buttons will be generated, with a setText() of one button being dog
so you are saying you want a listView with 4 buttons on each row.
Do this, _i am taking relevant portions.
private ListView listview; //your listview
private TagAdapter adapter; // your adapter
//we are in oncreate
//i have no knowledge on cdata so bare with me here
//now remove List<Button> data; from your code
we have jumped to the TagAdapter class
private Context context;
//private List<Button> taglist; remove this also
private ArrayList<TheClassThatContainsTags> myTags;//i am assuming this will be cdata or?
//but this list should contain what setText() for a button will get its text
public TagAdapter(Context context) { //this is how your constructor will look
super(context);
Log.i("Test", "constructor " );
this.context = context;
//here you start your async task and put your async task logic here
//if the async task requires some objects or items which is not in this class
// since this is a separate class, you can inject them, when i say inject
// put them in the constructor of TagAdapter like you inject the Context
//object instance, so it might change to
// public TagAdapter(Context context,OneMoreClassIfIWant omciiw) {
// here you aysnc task will execute, now when onPostExecute is triggered/
//called you will do the following, but so remove all the code lines
// you currently have under onPostExecute
// onPostExecute has triggered
myTags = // the tag items result from onpostExecute
//now your myTags Arraylist of type TheClassThatContainsTags has been
//instantiated
}
we are now moving to getCount still in your custom adapter
#Override
public int getCount() {
return (myTags == null) ? 0 : myTags.size();
}
we are now moving to getView still in your custom adapter
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
//in your posted getview, did you edit that too? if not does it give you errors?
//nevermind
// what you do here is check if convertView is null and instantiate it
// the position here in your method parameter is the index in your myTags
// list
if(convertView == null){
//guess you know how to do this. it should be the same as your old
//getview minus this final Button tag = taglist.get(position);
// and the line below it.
}
//here we are still in the getview - what you do is ,
you find what particular button you want by convertView.findViewById()
//my understanding as i pointer out is you want to have 4 buttons in a row
//it should be something like this
Button b = convertView.findViewById(R.id.button1);
b.setText(getItem(position));//getItem() is an instance method for the
//class you are extending, and it returns an Object of Type T, which in my
//example is TheClassThatContainsTags.class;
// and you can do the same for the next 3 buttons
}
we are out of your getview and custom adapter class , and we are in your oncreate .
here set when you need your tags then you do
tagAdapter = new TagAdapter(context,anyIfDesired_OtherInjections);
listview.setAdatper(tagAdapter);
now you are done. Hope it helps, also please read listview and Arraylist Adapter so you get a foresight of what you are doing and what i have posted here. it will help you trim down the hours you waste, if you spend 12 hours on the docs your will spend 5 minutes writing this and the next time you want to replicate it will be the same 5 minutes.
Be good sir and wish you success.
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().
For Example, like Google+ there are one big size and two small size display alternately until reach the last view. So is it possible to do this.
Like this picture:
http://upic.me/show/42297666
Google+ show each item in different size.
Thanks.
Yes.
1) You create a layout (my_layout) take care of alignments
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:padding="1dp"
android:layout_gravity="left"
android:orientation="horizontal" >
<ImageView
android:id="#+id/contentImage1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="5dp"
android:visibility="invisible"
android:src="#drawable/browse_product_thumbnail" />
<ImageView
android:id="#+id/contentImage2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="5dp"
android:visibility="invisible"
android:src="#drawable/browse_product_thumbnail" />
2) Now write and adapter for this and getView() method . Something like below code
public class ItemListAdapter extends ArrayAdapter<LaunchItem> {
private int _resource;
private LayoutInflater _inflater;
private static Launcher _browse;
private static final String tag = "Adapterr";
public ItemListAdapter(Launcher activity , int resourceId, List<LaunchItem> objects)
{
super( activity, resourceId, objects );
_resource = resourceId;
_inflater = LayoutInflater.from(activity);
this._browse = activity;
}
#Override
public View getView ( int position, View convertView, ViewGroup parent ) {
convertView = ( LinearLayout ) _inflater.inflate( _resource, null );
String imagePath = "";
String name = "";
LaunchItem item = getItem( position );
}
}
You can decide what to display and their visibility on getView .
3) Use the custom adapter in your code .
List<LaunchItem> lList = new ArrayList<LaunchItem>();
lList.add(new LaunchItem(image1,image2 );
ItemListAdapter data = new ItemListAdapter (this,R.layout.my_layout,lList);
view.setAdapter(data);
-Preeya