Setting TextView visible(or gone) in ListView - android

I am tying to set a textview inside my ListView visible depending on another variable. But when I try
TextView sdate;
TextView stime;
sdate= (TextView) findViewById(R.id.date);
stime= (TextView) findViewById(R.id.time);
It seems like it can't find the 2 in the layout?
From what I gather, there needs to be something in front of the findViewbyId() but I'm not sure on what. The items layout in the list is done by list_item.xml. The code that is handling all this is:
ListAdapter adapter;
if(add.equals("Event")){
stime.setVisibility(View.VISIBLE);
sdate.setVisibility(View.VISIBLE);
adapter = new SimpleAdapter(
AllSpotsActivity.this, spotsList,
R.layout.list_item, new String[] { TAG_PID,
TAG_NAME, "sdistance","dateof","timeof" }, new int[] {
R.id.pid, R.id.name, R.id.distance, R.id.date, R.id.time});
}else{
adapter = new SimpleAdapter(
AllSpotsActivity.this, spotsList,
R.layout.list_item, new String[] { TAG_PID,
TAG_NAME, "sdistance" }, new int[] {
R.id.pid, R.id.name, R.id.distance });
}
Thank you in advance,
Tyler
EDIT:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#drawable/gradient_background"
>
<!-- Product id (pid) - will be HIDDEN - used to pass to other activity -->
<TextView
android:id="#+id/pid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<!-- Name Label -->
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="6dip"
android:paddingLeft="6dip"
android:textSize="17dip"
android:textStyle="bold" />
<!-- Name Label -->
<TextView
android:id="#+id/distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingRight="6dip"/>
<TextView
android:id="#+id/date"
android:layout_below="#id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="12dip"
android:visibility="gone"/>
<TextView
android:id="#+id/time"
android:layout_below="#id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingRight="6dip"
android:visibility="gone"/>
</RelativeLayout>
EDIT 2:
I've also tried using lv.findViewById() because lv=getListView(); But that did not work either.

I think you should call findViewById() on each row's view. For example, if you are calling that method from the getView() method of your adapter, you should use convertView.findViewById.

If you want to have anything more than a simple TextView as the layout for each item in a ListView, what you'll need to do is create a custom adapter that extends ArrayAdapter. Inside of the getView() method of your custom adapter, you will have access to your custom xml layout (one of the arguments to the constructor of the ArrayAdapter is the resource ID of the layout file you want to have for each item in the list [e.g., R.layout.your_custom_list_item]). From inside of that method, you will have access to either a new or recycled view, which you can inflate your custom layout within.
The LayoutInflater.inflate() method you call from inside the getView() method will return you a view that you can call findViewById() on to get access to all the views in your custom layout that you want to interact with. It's there that you can make your views visible or invisible based on the data you pass into the adapter (the third argument to the adapter's constructor is either a list or an adapter with the data you want to use to populate the views). I strongly recommend you watch the I/O video on ListViews for a more complete explanation. I've also included some sample code for a custom adapter below.
public class BookingSearchResultsAdapter extends ArrayAdapter<SearchResult> {
private static final String TAG = BookingSearchResultsAdapter.class.getName();
private int mLayoutResourceId;
private Context mContext;
private List<SearchResult> mResults = null;
public BookingSearchResultsAdapter(Context context, int resource, List<SearchResult> results) {
super(context, resource, results);
mContext = context;
mLayoutResourceId = resource;
mResults = results;
}
/**
* #return A view to display search result
*/
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
SearchResultVendorViewHolder holder = null;
// if there is no recycled view available
if(row == null) {
Log.d(TAG, "No recyclable custom view found. New view created.");
// get a new search result view
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(mLayoutResourceId, parent, false);
// store all static view information in a holder
holder = new SearchResultVendorViewHolder();
holder.imgIcon = (ImageView) row.findViewById(R.id.search_result_establishment_icon);
holder.txtTitle = (TextView) row.findViewById(R.id.search_result_establishment_name);
holder.txtDescription = (TextView) row.findViewById(R.id.search_result_establishment_description);
// attach the holder to the view so that it can be recycled
row.setTag(holder);
}
else {
Log.d(TAG, "View recycled");
// get the recycled view (stored in tag)
holder = (SearchResultVendorViewHolder)row.getTag();
}
// initialize data in custom search result view
SearchResult result = (SearchResult) mResults.get(position);
holder.txtTitle.setText(result.getEstablishmentName());
holder.imgIcon.setImageResource(result.getImageId());
holder.txtDescription.setText(result.getDescription());
Log.d(TAG, "Custom search view data initialized");
return row;
}
static class SearchResultVendorViewHolder {
ImageView imgIcon;
TextView txtTitle;
TextView txtDescription;
}
}

Related

Android custom ArrayAdapter rendering Objects in list, not values

I'm trying to bind a custom layout (a LinearLayout containing two TextViews) to a Spinner. I subclassed ArrayAdapter (mostly) correctly. Selecting an item in the Spinner calls getView() correctly, setting the LinearLayout's TextViews' values correctly. The problem is the initial display of the items in the Spinner (when clicking on the Spinner) just shows Objects; not the TextViews they should be displaying. Only AFTER clicking on one of the Objects does the Spinner correctly set the TextViews using my custom adapter's getView() method. Here's the custom adapter class:
public class BusRouteAdapter extends ArrayAdapter<BusRoute> {
...
public BusRouteAdapter(Context context, int resource, int textViewId, ArrayList<BusRoute> routes) {
super(context, resource, textViewId, routes);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
BusRoute route = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bus_route, parent, false);
}
TextView tvBusRoute = (TextView) convertView.findViewById(R.id.tvBusRoute);
TextView tvBusRouteNumber = (TextView) convertView.findViewById(R.id.tvBusRouteNumber);
tvBusRoute.setText(route.routeName);
tvBusRoute.setTag(route.route);
tvBusRouteNumber.setText(route.route);
if (!route.routeColor.equals("")) {
tvBusRouteNumber.setBackgroundColor(Color.parseColor(route.routeColor));
}
return convertView;
}
}
Here's the layout that is to be used for each Spinner list item (bus_route.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
<TextView
android:id="#+id/tvBusRouteNumber"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.25"
android:padding="8dp" />
<TextView
android:id="#+id/tvBusRoute"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.75"
android:padding="8dp" />
</LinearLayout>
And in my Activity, I'm setting the adapter to a properly-populated list of BusRoute objects:
busRouteAdapter = new BusRouteAdapter(getBaseContext(), R.layout.bus_route, R.id.tvBusRoute, arrayOfBusRoutes);
routesSpinner.setAdapter(busRouteAdapter);
It does seem strange that I need to pass the Layout id (R.layout.bus_route) AND one of the TextViews contained in that Layout (R.id.tvBusRoute).
Here's what is rendered when clicking on the Spinner:
But if I click one of the Objects, getView() is called, and the selected Layout and TextViews are rendered properly (apparently I selected "GMU - Pentagon"):
What am I missing to get the Spinner's popup list to display ALL my bus route items rendered correctly?
I think you need to override getDropDownView to deal with spinners
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
BusRoute route = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bus_route, parent, false);
}
TextView tvBusRoute = (TextView) convertView.findViewById(R.id.tvBusRoute);
TextView tvBusRouteNumber = (TextView) convertView.findViewById(R.id.tvBusRouteNumber);
tvBusRoute.setText(route.routeName);
tvBusRoute.setTag(route.route);
tvBusRouteNumber.setText(route.route);
if (!route.routeColor.equals("")) {
tvBusRouteNumber.setBackgroundColor(Color.parseColor(route.routeColor));
}
return convertView;
}

DB results into a ListView, data may vary

Hi a bit new to java/android programming, I am trying to populate a listview from a database. The problem is the database output for each record may have varying results. To give you an idea I have the following layout in my xml for the listview;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#a28d7a">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/coreHeader"
android:textColor="#ffffff"
android:padding="4dp" />
<LinearLayout
android:id="#+id/coreLinear"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="4dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/coreStatsLeft"
android:textColor="#ffffff" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/textView"
android:textColor="#ffffff"
android:textAlignment="textEnd"
android:gravity="right" />
</LinearLayout>
</LinearLayout>
The first TextView is the header of sorts, bigger font, etc.. in this area it will hold two fields from the database, the NAME and the LEVEL e.g; SPIDER-MAN (Lvl 5).
The two textfields below it will hold the stats, this area can have more than one for example;
Name Value
------------------------------------
Armor 10%
Speed 5%
... and so on
Each record can be different, some may not have speed, some may not have armor... Maybe this is too difficult to do via ListView, but I need it to be searchable and I do not know what other options I have available for this.
My database fields are as follows:
Id, Name, Level, Stats
an example of the populated db would read;
1, Spider-Man, 5, 3|10%;5|5%;6|3%
I created a example to show how to add variable data to each row in a listview.
This is the Activity implementation:
public class MainActivity extends AppCompatActivity
{
private DynamicAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Simulating variable data per row. Array Adapter instead Cursor Adapter for simplicity
final DataRow[] data =
{
new DataRow("Spider Man", new String[] {"3|10%", "5|25%"}),
new DataRow("Spider Man Brother", new String[] {"3|20%"}),
new DataRow("Other Spider Man", new String[] {"3|22%", "1|12%", "4|7%"})
};
// Assign data to adapter
adapter = new DynamicAdapter(this, data);
// Getting reference to ListView
ListView listViewData = (ListView) findViewById(R.id.listViewData);
// Setting adapter to listView
listViewData.setAdapter(adapter);
}
}
This is how the Adapter will put the data for each row:
public class DynamicAdapter extends ArrayAdapter<DataRow>
{
private final Context context;
private final DataRow[] data;
public DynamicAdapter(Context context, DataRow[] data)
{
super(context, R.layout.row_layout, data);
this.context = context;
this.data = data;
}
#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.row_layout, parent, false);
// Get a listview reference
LinearLayout linearLayoutRow = (LinearLayout) rowView.findViewById(R.id.coreLinear);
if(position < data.length)
{
// Put text on header
TextView textHeader = (TextView) rowView.findViewById(R.id.coreHeader);
// Set the header for this row
textHeader.setText(data[position].GetHeader());
// Creating a vertical linear layout to put the data row
LinearLayout linearLayoutData = new LinearLayout(context);
linearLayoutData.setOrientation(LinearLayout.VERTICAL);
// Get column amount for this row.
int columnAmount = data[position].GetColumnsSize();
for(int i = 0; i < columnAmount; i++)
{
// Creating dynamically a TextView for this column.
TextView dynamicData = new TextView(context);
dynamicData.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.WRAP_CONTENT));
// Adding data to TextView
dynamicData.setText(data[position].GetDataAt(i));
// Adding TextView to linearLayout
linearLayoutData.addView(dynamicData);
}
// Adding LinearLayout to LinearLayout on XML
linearLayoutRow.addView(linearLayoutData);
}
return rowView;
}
}
This is the full demo on Github: https://github.com/deinier/DynamicDataOnListView
I hope this help.

Android custom ArrayAdapter<String> becomes super slow

I'm learning Android, and following this tutorial on custom ListView Items.
However, I've created my own ListView item and when I load up the app (on my Galaxy S4, physical device) it becomes incredibly slow.
When I use a simple_list_item_1 for my listview, everything runs smooth, but when I use my own custom item it runs super slow. I can't find out why this is. There seem to be no expensive (and definitely not infinitely running) operations that I created.
I've also noticed that even tho I have only 5 listItems, the getView method gets called around 15 times. An explanation to why this is would also be welcome. (They might be related)
For my Activity I used Android Studio (1.2.2) standard "Navigation Drawer Activity". I've only been adding stuff in the onCreateView method. Which now looks like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
/* Start of my custom code */
//Create some list items
String[] words = {"Defenestration", "Indicative", "Executive", "Developmental", "Consciousness"};
//The list in the Fragment
ListView list = (ListView) rootView.findViewById(R.id.mainList);
//The custom ListAdapter
ListAdapter la = new ShaggyAdapter(getActivity(), words);
//A built in listadapter for testing
//ListAdapter la2 = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, words);
list.setAdapter(la);
//Create listener
list.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String word = String.valueOf(parent.getItemAtPosition(position));
Toast.makeText(getActivity(), word, Toast.LENGTH_SHORT).show();
}
});
/* End of my custom code */
return rootView;
}
The custom adapter looks like this:
class ShaggyAdapter extends ArrayAdapter<String>{
private static final String TAG = "coo";
public ShaggyAdapter(Context context, String[] words) {
super(context, R.layout.shaggy_item, words);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null){
convertView = inflater.inflate(R.layout.shaggy_item, parent, false);
Log.i(TAG, "inflate");
}else{
Log.i(TAG, "Don't inflate");
}
String word = getItem(position);
TextView name = (TextView) convertView.findViewById(R.id.itemName);
name.setText(word);
return convertView;
}
}
The custom List Item looks like this:
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:columnCount="5">
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:id="#+id/itemImage"
android:layout_row="0"
android:layout_column="0"
android:src="#drawable/no_profile"
android:layout_margin="8dp"
android:layout_rowSpan="2"
android:contentDescription="#string/shaggy_item_image_description" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="#string/shaggy_item_name_placeholder"
android:id="#+id/itemName"
android:layout_row="0"
android:layout_column="1"
android:layout_margin="8dp"
android:layout_marginTop="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="#string/shaggy_item_new_tag"
android:id="#+id/itemNew"
android:layout_row="0"
android:layout_column="2"
android:layout_marginTop="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="#string/shaggy_item_date_placeholder"
android:id="#+id/itemDate"
android:layout_row="1"
android:layout_column="1"
android:layout_margin="8dp"
android:layout_columnSpan="2" />
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:id="#+id/itemStar"
android:layout_row="0"
android:layout_column="3"
android:src="#drawable/rating_star_1"
android:layout_margin="8dp"
android:layout_marginTop="14dp"
android:layout_rowSpan="2"
android:contentDescription="#string/shaggy_item_star_description" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="#string/shaggy_item_rating_placheholder"
android:id="#+id/itemRating"
android:layout_row="0"
android:layout_column="4"
android:layout_margin="8dp"
android:layout_marginTop="14dp"
android:layout_rowSpan="2" />
</GridLayout>
Any suggestions would be highly appreciated.
I found the answer, I made a very silly mistake. The image I was using in the profile image view was 2000x2000px and I displayed it in a 80x80dp imageview. I noticed memory usage suddenly doubled.
Using a smaller image (currently 300x300px) made everything run super smooth. What I've learned today:
- Use correctly sized images! Android doesn't like handling images.
I will also be using the Holding Pattern as suggested by Boss and King of Masses to make it extra smooth.
why findViewById is so slow? And why View Holder
Pattern is faster?
When you are not using Holder so getView() method will call findViewById() as many times as you row(s) will be out of View. So if you have 1000 rows in List and 990 rows will be out of View then 990 times will be called findViewById() again.
Holder design pattern is used for View caching - Holder (arbitrary) object holds child widgets of each row and when row is out of View then findViewById() won't be called but View will be recycled and widgets will be obtained from Holder.
if (convertView == null) {
convertView = inflater.inflate(layout, null, false);
holder = new Holder(convertView);
convertView.setTag(holder); // setting Holder as arbitrary object for row
}
else { // view recycling
// row already contains Holder object
holder = (Holder) convertView.getTag();
}
// set up row data from holder
titleText.setText(holder.getTitle().getText().toString());
Where Holder class can looks like:
public class Holder {
private View row;
private TextView title;
public Holder(View row) {
this.row = row;
}
public TextView getTitle() {
if (title == null) {
title = (TextView) row.findViewById(R.id.title);
}
return title;
}
}
Here is second approach how to use ViewHolder pattern:
ViewHolder holder;
// view is creating
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.row, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
}
// view is recycling
else {
holder = (ViewHolder) convertView.getTag();
}
// set-up row
final MyItem item = mItems.get(position);
holder.title.setText(item.getTitle());
...
private static class ViewHolder {
public TextView title;
public ImageView icon;
}
This Android listview using ViewHolder will help you to implement the same.
As everybody know, Google and AppCompat v7 as support library released new ViewGroup called RecyclerView that is designed for rendering any adapter-based views.
Cheers !!

Android Custom Adapter: list items only populated when scrolling

I'm having an issue getting my list populated correctly by my custom ArrayAdapter (code below). As I understand it, my adapter is only populating the textviewResourceId when it is instanciated since I'm using constructor Adapter(context, rowLayout, textViewResourceId, ArrayList<Items>), but the getView method is only called when rows that were not visible become visible.
This is causing an issue as, when my list is first showing, only the title of my article is showing, and I have to scroll all the way down the list and up for all the views in each row to be populated correctly (since that task is done in getView).
Can anyone point me in the right direction? How could I refactor this so all views in each visible row gets populated right away?
Code to my custom adapter:
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class ArticleArrayAdapter extends ArrayAdapter<Article> {
private final Context context;
private final ArrayList<Article> articles;
#SuppressWarnings("unused")
private final int rowLayout;
public ArticleArrayAdapter(Context context, int rowLayout, int textViewResourceId, ArrayList<Article> articles) {
super(context, rowLayout, textViewResourceId, articles);
this.rowLayout=rowLayout;
this.context = context;
this.articles = articles;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(R.layout.affichageitem, null);
}
else {
TextView viewTitre = (TextView)row.findViewById(R.id.titre);
TextView viewAuteur = (TextView)row.findViewById(R.id.auteur);
TextView viewDate = (TextView)row.findViewById(R.id.date);
ImageView viewLogo = (ImageView)row.findViewById(R.id.category_logo);
viewTitre.setText(articles.get(position).getTitle());
viewAuteur.setText(articles.get(position).getCreator());
viewDate.setText(articles.get(position).getDate());
Drawable drawLogo = context.getResources().getDrawable(R.drawable.logocat);
viewLogo.setImageDrawable(drawLogo);
}
return super.getView(position, convertView, parent);
}
}
Edited version:
public class ArticleArrayAdapter extends ArrayAdapter<Article> {
private final Context context;
#SuppressWarnings("unused")
private final int rowLayout;
public ArticleArrayAdapter(Context context, int rowLayout,int textViewResourceId) {
super(context, rowLayout, textViewResourceId);
this.rowLayout=rowLayout;
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(R.layout.affichageitem, null);
}
else {
TextView viewTitre = (TextView)row.findViewById(R.id.titre);
TextView viewAuteur = (TextView)row.findViewById(R.id.auteur);
TextView viewDate = (TextView)row.findViewById(R.id.date);
ImageView viewLogo = (ImageView)row.findViewById(R.id.category_logo);
viewTitre.setText(getItem(position).getTitle());
viewAuteur.setText(getItem(position).getCreator());
viewDate.setText(getItem(position).getDate());
Drawable drawLogo = context.getResources().getDrawable(R.drawable.logocat);
viewLogo.setImageDrawable(drawLogo);
}
return super.getView(position, convertView, parent); // <<- ONLY TITLES
//return row; <<- EMPTY
}
}
rowLayout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="#+id/category_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="#string/logo_desc"
android:padding="20dp" />
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="5dp" >
<TextView
android:id="#+id/titre"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18dp"
android:textStyle="bold" />
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity=""
android:orientation="horizontal" >
<TextView
android:id="#+id/auteur"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:textSize="12dp" />
<TextView
android:id="#+id/espace"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/espace"
android:adjustViewBounds="true"
android:textSize="12dp" />
<TextView
android:id="#+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:textSize="12dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
The problem is that you are not populating new views. What happens is that Android may keep a fixed number of views which will be used for your list view. The views are recycled which is why it's impossible to "populate" all your views before they become visible. This line
if (view == null) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(R.layout.affichageitem, null);
}
checks whether a view is being recycled or not. null means it's not, so if you get null you need to inflate a new view. Upto there your code's fine. However, you need to populate the view whether it's a newly inflated view or not. So you shouldn't have the else statement, just have
View row = convertView;
if (row == null) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(R.layout.affichageitem, null);
}
TextView viewTitre = (TextView)row.findViewById(R.id.titre);
TextView viewAuteur = (TextView)row.findViewById(R.id.auteur);
TextView viewDate = (TextView)row.findViewById(R.id.date);
ImageView viewLogo = (ImageView)row.findViewById(R.id.category_logo);
viewTitre.setText(getItem(position).getTitle());
viewAuteur.setText(getItem(position).getCreator());
viewDate.setText(getItem(position).getDate());
Drawable drawLogo = context.getResources().getDrawable(R.drawable.logocat);
viewLogo.setImageDrawable(drawLogo);
return row;
The reason why it worked when you scrolled all the way down is that on your way back up getView was receiving recycled views and it jumped right into the else clause you had.
You are using your own collection ArrayList<Article>.
Note that every ArrayAdaper<foo> already has data collection built in, where you can add by add(foo) or addAll(List<foo>) and clear it by clear() method.
Also, ListView can observe this data and refresh when changes happen to this data. Or explicitly when notifyDataSetChanged() is called on adapter.
Problem here is that you are accepting data in constructor, storing in yet another local variable, and notifyDataSetChanged() is not being called. You cannot call it from constructor as Object is still under construction.
So, Don't accept data in constructor. Inside getView() use getItem(position) to get Article item.
Add data externally like:
ArticleArrayAdapter adapter = new ArticleArrayAdapter(context,rowLayout,android.R.layout.simple_list_item_1);
adapter.addAll(articles);
myListView.setAdapter(adapter);
Looks correct to me - only thing: there is no need to call the superclass. Try to return your assembled view like that:
return row;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row==null){
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(R.layout.affichageitem, null);
convertView.setTag(row);
}else{
TextView viewTitre = (TextView)row.findViewById(R.id.titre);
TextView viewAuteur = (TextView)row.findViewById(R.id.auteur);
TextView viewDate = (TextView)row.findViewById(R.id.date);
ImageView viewLogo = (ImageView)row.findViewById(R.id.category_logo);
viewTitre.setText(getItem(position).getTitle());
viewAuteur.setText(getItem(position).getCreator());
viewDate.setText(getItem(position).getDate());
Drawable drawLogo = context.getResources().getDrawable(R.drawable.logocat);
viewLogo.setImageDrawable(drawLogo);
}
}
I had this similar kind of issue. I also found that without scrolling manually to the last of the list all views were not created. All items were null except visible items.So, I had to scroll down to the last of the list programmatically.
I have extended MyAdapter from BaseAdapter class.
mAdapter = new MyAdapter(this, mFinalContactList);
mListView.setAdapter(mAdapter);
To auto scrolling to last with all listview created I have used following lines of code.
mAdapter.notifyDataSetChanged();
mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
mListView.smoothScrollToPosition(mFinalContactList.size()-1);
This might help some one who are trying auto scroll to the last.
N.B. mListView.setSelection(position); method only can point the last list item if we set the position to last. But can not populate the list item from forst to last.
Thank you

Removing an Item with a Button in ListView with Custom ArrayAdapter

I have custom list_row :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content" android:baselineAligned="false">
<Button android:layout_width="30dip" android:layout_marginTop="7dip" android:gravity="right"
android:id="#+id/delete" android:layout_height="30dip" android:background="#drawable/delete"
android:layout_gravity="top"></Button>
<TextView android:textSize="20dip"
android:text="TextView" android:id="#+id/tavsiye" android:layout_marginTop="10dip"
android:layout_gravity="top" android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
I have a ListView like that:
<ListView
android:id="#+id/tavsiyeler"
android:layout_height="300dip"
android:layout_width="170dip"
android:fastScrollEnabled="true"
android:scrollbars="vertical"/>
and a custom adapter which extends ArrayAdapter :
public class HekimTavsiyeleriAdapter extends ArrayAdapter<String> {
private Context context;
private int resource;
private ArrayList<String> tavsiyeler;
public HekimTavsiyeleriAdapter(Context context, int resource,
ArrayList<String> objects) {
super(context, resource, objects);
this.context=context;
this.resource=resource;
this.tavsiyeler=objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(this.resource, null);
}
if (this.tavsiyeler.size()!=0) {
TextView tavsiye = (TextView) v.findViewById(R.id.tavsiye);
Button but= (Button) v.findViewById(R.id.delete);
if (tavsiye != null) {
String st=this.tavsiyeler.get(position);
tavsiye.setText(st);
}
if( but!=null){
but.setId(position);
but.setOnClickListener(new AdapterView.OnClickListener() {
#Override
public void onClick(View v) {
int id=v.getId();
tavsiyeler.remove(id);
notifyDataSetChanged();
}
});
}
}
return v;
}
I am creating adapter and fill the list like that :
eklenecekTavsiyeler=new ArrayList<String>();
adapter= new HekimTavsiyeleriAdapter(context,
R.layout.hekim_tavsiyeleri_row, eklenecekTavsiyeler);
ListView tavsiyelerListesi = (ListView)findViewById(R.id.tavsiyeler);
tavsiyelerListesi.setAdapter(adapter);
And adding new items like that:
this.adapter.add(<some-string>);
this.adapter.notifyDataSetChanged();
and my list view is seen like that:
http://imageshack.us/photo/my-images/97/listir.jpg/
Here is my question:
I am adding new items to the list. I have fixed height for the list. When I fill the list until all height is occupied, then I add one new item to the list which requires scrolling becasue overflow in list height. The last item I added gets wrong id and when I pressed the cross button, it removes wrong item. However, when the list is not overflowed, everything works fine. After overflow, the ids of buttons are set wrongly (seems randomly). By the way, for setting the button's id, I am using getView's position argument.
Thanks in advance.
I am afraid that you have flaw in the code.
You have to stop calling but.setId(). With this you are overriding internal id of the view which is the value of R.id.delete. Probably you meant to use but.setTag() / but.getTag()?

Categories

Resources