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().
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 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.
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.
I am facing EXTREMELY PECULIAR problem with my android application. I see not a single similar solution anywhere, either on google or on SO.
Here is my screenshot of the app:
This is normal expected output. But when I exit the app and resume again from launcher, often(say 2 out of 5 times) I happen to get the white components(list view and EditText) like this:
In this image, I have touched the first element of listview while taking screenshot so that its shown that the listview items are having actual content and not empty.
Here is my layout resource file main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ll"
android:cacheColorHint="#00000000"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" android:weightSum="15" android:background="#android:color/white">
<EditText
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/edittext" android:layout_weight="2" android:background="#ffffff"
android:textColor="#android:color/black" android:gravity="center" android:hint="Enter Your Text Here"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp" android:layout_weight="2"
android:weightSum="12" android:gravity="center">
<Button android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Tweet"
android:id="#+id/tweetbtn"
android:background="#drawable/mybutton"
android:layout_weight="6"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Search"
android:background="#drawable/mybutton"
android:id="#+id/searchbtn"
android:layout_weight="6"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Most Frequently Tweeted"
android:id="#+id/listviewlabel" android:layout_weight="1" android:gravity="center" android:background="#adadad"
android:textColor="#android:color/black"/>
<ListView
android:cacheColorHint="#00000000"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/listView" android:layout_gravity="center_horizontal" android:layout_weight="10"
android:choiceMode="singleChoice"/>
</LinearLayout>
Please someone help me out with this. Atleast help me resolve the white EditText issue first. That will give me alteast a clue to solve the listview issue.
EDIT:
The listview is dynamically populated by elements. Here is my onStart() method:
#Override
public void onStart(){
super.onStart();
handleFrequentMenuSelected();
}
Here is the handleFrequentMenuSelected():
private void handleFrequentMenuSelected() {
if(!isAccountAdded()){
showToast("Add an account first to get started! Goto Menu and select account.");
}else{
List<StatusElement>aList=getStatusElementsFromSQLiteDatabase();
HashMap<String,Integer> hMap=new HashMap<String, Integer>();
for(StatusElement s:aList){
String tokens[]=s.toString().split(" ");
String outText="";
if(tokens.length>1){
if(tokens[0].contains("/")){
String tokens2[]=tokens[0].split("/");
try{
long l=Long.parseLong(tokens2[0]);
for(int i=1;i<tokens.length;i++){
outText=outText+tokens[i]+" ";
}
}catch(Exception e){
outText=s.toString();
}
}else{
try{
long l=Long.parseLong(tokens[0]);
for(int i=1;i<tokens.length;i++){
outText=outText+tokens[i]+" ";
}
}catch(Exception e){
outText=s.toString();
}
}
}else{
outText=s.toString();
}
outText=outText.trim();
if(hMap.containsKey(outText)){
int cnt=hMap.get(outText);
cnt++;
hMap.put(outText,cnt);
}else{
hMap.put(outText,1);
}
}
hMap= (HashMap<String, Integer>) StaticConstants.sortByValue(hMap);
ArrayList<String>tweets=new ArrayList<String>();
ArrayList<Integer>frequencies=new ArrayList<Integer>();
ArrayAdapter<String>adapter;
int count=0;
for(String s:hMap.keySet()){
tweets.add(s);
frequencies.add(hMap.get(s));
count++;
if(count==50)
break;
}
adapter=new MyCustomFrequentArrayAdapter(this,tweets,frequencies);
listView.setAdapter(adapter);
listViewLabel.setText("Most Frequent Tweets");
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
final String item = (String) parent.getItemAtPosition(position);
editText.setText(System.currentTimeMillis()+" "+item);
}
});
}
}
Here is my MyCustomFrequentArrayAdapter:
class MyCustomFrequentArrayAdapter extends ArrayAdapter<String> {
private final Context context;
private final ArrayList<String> values;
private final ArrayList<Integer>frequencies;
public MyCustomFrequentArrayAdapter(Context context, ArrayList<String> values,ArrayList<Integer>frequencies) {
super(context, R.layout.customlistview, values);
this.context = context;
this.values = values;
this.frequencies=frequencies;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.customlistview, parent, false);
TextView textView1 = (TextView) rowView.findViewById(R.id.firstLine);
TextView textView2 = (TextView) rowView.findViewById(R.id.secondLine);
Log.d("Position",""+position);
//Extracting first six words
String s=values.get(position);
String tokens[]=s.split(" ");
String dispText="";
if(tokens.length>6){
for(int i=0;i<6;i++){
dispText=dispText+tokens[i]+" ";
}
}else{
dispText=s;
}
textView2.setText(dispText);
textView1.setText("Frequency:"+frequencies.get(position));
return rowView;
}
}
Referencing a blog post by Romain Guy - Why Is My List Black
ListView has top and bottom fading edges to indicate it is scrollable.
Creating the fading edge has performance issues so ListView has an optimization to improve performance. Unfortunately the optimization causes problems if the background of the ListView is set to something other than the default.
The optimization can be disabled by setting android:cacheColorHint="#00000000" as you are doing BUT quoting from the blog post...
To fix this issue, all you have to do is either disable the cache color hint optimization, if you use a non-solid color background, or set the hint to the appropriate solid color value.
In other words using android:cacheColorHint="#00000000" should only be used for a "non-solid color" (one which is transparent / translucent).
In your case you are using #ffffff which is an RGB value and by default that means its 'A' component (the alpha) will be ff making it fully opaque, i.e., "solid".
So referring to the last part of the above quote...
...set the hint to the appropriate solid color value.
This suggests you should use android:cacheColorHint="#ffffff" to fix the ListView problem.
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 ,.