headerView does not scroll with the listview Android - android

I am using a DragSortListView and i want a header which will scroll down and up with the list. I have no idea why the header is not scrolling with the list. I use the listview in a fragment and i added the header like this:
public void onViewCreated(View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
DragSortListView cursListView = (DragSortListView) view.findViewById(R.id.drag_list);
LayoutInflater inflater = (LayoutInflater) Utils.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
titleLayout = inflater.inflate(R.layout.title_row, null);
cursListView.addHeaderView(titleLayout);
setTitle(titleName, titleValue);
cursListView.setAdapter(cursorAdapter);}
setTitle sets the values for the header and Utils.getContext() return the context of the Application.
public void setTitle(String currency, float value) {
((TextView) titleLayout.findViewById(R.id.titleName)).setText(currency);
((EditText) titleLayout.findViewById(R.id.titleValue)).setText(String.valueOf(value));
((EditText) titleLayout.findViewById(R.id.titleValue)).setImeActionLabel(getString(R.string.convert), EditorInfo.IME_ACTION_DONE);
((EditText) titleLayout.findViewById(R.id.titleValue)).setOnEditorActionListener(convertCurrencies);
restartLoader();
}

Why not create the illusion of a header?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
This way the TextView, in this case, will always stay on top, the ListView can still scroll, which is the desired result if I understand your question correctly.

i think you have first understand what is Header of Footer. Header means that is Always on Top and visible in any Condition same as Footer which is always on bottom and visible.that same concept use for HeaderView and FooterView in listview in android.
So Achive your goal Add one item as header and get it in your Adapterclass getView method and Display it. if there are only one header then at 0 position Your Header available and other position your item available. and it is scroll with your list.
Thats it...

Related

Problems with click listener for header in a ListView

So, I have a header view defined as follows:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp">
<TextView android:id="#+id/purchase_menu_header_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="20sp"
android:text="#string/purchase_options_label"/>
</LinearLayout>
Inflated as follows:
View header = ((Activity) context).getLayoutInflater().inflate(R.layout.purchase_menu_header, options, false);
options.addHeaderView(header);
I have an click listener for items in the options ListView:
options.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Offer offer = (Offer) options.getItemAtPosition(position);
initiatePurchase(offer.getStoreProduct());
}
});
And a click listener for the header view itself:
header.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
baseLayout.removeView(background);
baseLayout.removeView(overlay);
}
});
My problem is that the header only registers clicks on the text portion of the header. The desired behaviour is to have the entire header clickable. I have tried solutions such as using setOnItemClickListener with a getItemAtPosition(0), but this returns null. Have also tried to expand the text view in the header with MATCH_PARENT, but no luck there.
Try making your LinearLayout clickable using the android:clickable attribute.
My problem is that the header only registers clicks on the text
portion of the header.
Cause your header is just the TextView with wrap_content as width and height. Hence you are applying clicklistener to TextView with restricted clickable area.
Solution:
use match_parent as width for TextView. Or
use the LinearLayout that contains the TextView in it, as the header and make that clikable.
Hope it helps you.

Why does ListView stays above TextView in ListPreference dialog?

I need to create a custom ListPreference dialog so that I can add some header text (a TextView) above the List (ListView).
I've created MyListPreference class that extends ListPreference and overrides onCreateDialogView():
#Override
protected View onCreateDialogView() {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = (View) inflater.inflate(R.layout.dialog_preference_list, null);
return v;
}
My XML layout dialog_preference_list.xml contains:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<ListView
android:id="#android:id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false"
android:scrollbarAlwaysDrawVerticalTrack="true" />
</LinearLayout>
Problem: The TextView is displayed below the ListView instead of above. I need the TextView to be above. I've tried both with LinearLayout and RelativeLayout (using "below" or "above" attributes) with no success: I can't find a way to put the TextView above the ListView... The layout is pretty simple and I cannot see why the list stays above...
Also, note that the problem occurs on both a real device (Nexus 4, Android 4.2.2) and the emulator. However, when looking at the layout rendered in Eclipse's graphical layout, the layout is correct! See both attached pictures.
Any idea on how to solve this?
Layout rendered on the device (incorrect):
Layout rendered on Eclipse (correct):
Edit with solution 10.07.2013
As suggested by the accepted answer, the problem comes from the use of builder.setSingleChoiceItems() in ListPreference's onPrepareDialogBuilder().
I've fixed it by extending ListPreference and overriding onCreateDialogView() to build the Dialog without the builder so that I can create a custom View showing the header text above the list items.
GPListPreference.java:
public class GPListPreference extends ListPreference {
...
#Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
builder.setNegativeButton(null, null);
builder.setPositiveButton(null, null);
}
private int getValueIndex() {
return findIndexOfValue(getValue());
}
#Override
protected View onCreateDialogView() {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListView lv = (ListView) inflater.inflate(R.layout.dialog_preference_list, null);
TextView header = (TextView) inflater.inflate(R.layout.dialog_preference_list_header, null);
header.setText(getDialogMessage()); // you should set the header text as android:dialogMessage in the preference XML
lv.addHeaderView(header);
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(), R.layout.dialog_preference_list_singlechoice, getEntries());
lv.setAdapter(adapter);
lv.setClickable(true);
lv.setEnabled(true);
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
lv.setItemChecked(getValueIndex() + 1, true);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
setValueIndex(position - 1);
getDialog().dismiss();
}
});
return lv;
}
}
dialog_preference_list.xml:
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false"
android:scrollbarAlwaysDrawVerticalTrack="true" />
dialog_preference_list_singlechoice.xml
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="2dip"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:paddingTop="2dip"
android:textAppearance="?android:attr/textAppearanceMedium" />
dialog_preference_list_header.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dip"
android:textAppearance="?android:attr/textAppearanceSmall">
</TextView>
I think the problem is with the way ListPreference works. ListPreference uses Builder.setSingleChoiceItems() to create the rows with the RadioButtons, and it has preference over the custom layout you are trying to add (in your case a TextView and a ListView inside a LinearLayout. The solution is extending DialogPreference instead. Here is a link to a GitHub where I created a custom DialogPreference that does what you need. I haven't coded the RadioButton logic.
I guess it's a theming issue. Try changing the theme of your dialog inside the constructor make it something like setStyle(STYLE_NO_TITLE, R.style.AppTheme). Your base app theme with no_title style.
If this is not the issue than it might be related with the ListPreference class itself. It might be overriding your layout for consistency in theming the preference views. However, I have not used ListPreference before, so its just a guess.
Can you reproduce the same result by playing with the themes in XML graphical layout preview?
Another option you can try is to add the TextView as a header to the ListView like this:
TextView textView = new TextView(getActivity());
ListView listView = new ListView(getActivity());
listView.addHeaderView(textView);
The addHeaderView takes a View so you theoretically have anything you want to be the header, but I have only used a TextView.
The link above is broken. On this solution the idea is overriding the ListPreference, and inflating your own listview, with the data defined on the ListPreference.
#Override
protected View onCreateDialogView() {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListView lv = new ListView(getContext());
// Inflate the view into the header only if a message was set
if (getDialogMessage() != null && ! getDialogMessage().equals("") ) {
TextView header = (TextView) inflater.inflate(R.layout.dialog_preference_list_header, null);
header.setText(getDialogMessage());
lv.addHeaderView(header, null, false);
}
// Create a new adapter and a list view and feed it with the ListPreference entries
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(),
R.layout.custom_dialog_single_choice_list_adapter, getEntries());
lv.setAdapter(adapter);
lv.setClickable(true);
lv.setEnabled(true);
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
lv.setItemChecked(getValueIndex() + 1, true);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
setValueIndex(position - 1);
getDialog().dismiss();
}
});
return lv;
}
Another important thing is to call onPrepareDialogBuilder and not calling super in it. This will avoid that the listview appears twice.
#Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
// Not calling super, to avoid having 2 listviews
// Set the positive button as null
builder.setPositiveButton(null, null);
}
private int getValueIndex() {
return findIndexOfValue(getValue());
}
Where dialog_preference_list_header is in my case only a TestView, but it could be a more complex view, and custom_dialog_single_choice_list_adapter could be something like this:
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="2dip"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:paddingTop="2dip"
android:textAppearance="?android:attr/textAppearanceMedium" />

Android: ListView with expanding LinearLayouts as items causes duplicates

I'm trying to write a test application that consists of a few fragments.
One fragment should contain a listView of all music artists from the device.
Each item of this list is a linearlayout starting with a TextView with the artist name and an empty linearlayout under it as follows:
The list is of this layout:
<ListView
android:id="#+id/artistsLists"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
</ListView>
Each item is of the following layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/artistName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="" />
<LinearLayout
android:id="#+id/artistsAlbums"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
I'm populating the list using a SimpleCursorAdapter in the following way:
public class MusicTabFragment extends Fragment
{
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_music_tab,container,false);
Cursor artistsCursor = getActivity().getContentResolver().query(Audio.Artists.EXTERNAL_CONTENT_URI, new String[]{Audio.Artists.ARTIST,Audio.Artists._ID}, null, null,Audio.Artists.ARTIST);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(view.getContext(), R.layout.music_artist_list_item_layout, artistsCursor, new String[]{Audio.Artists.ARTIST},new int[]{R.id.artistName},0 );
ListView lView = (ListView)view.findViewById(R.id.artistsLists);
lView.setAdapter(adapter);
lView.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
((LinearLayout)view.findViewById(R.id.artistsAlbums)).removeAllViews();
Cursor albumsCursor = getActivity().getContentResolver().query(Audio.Artists.Albums.getContentUri("external", ((Cursor)parent.getItemAtPosition(position)).getLong(1)), new String[]{Audio.Albums.ALBUM, Audio.Albums._ID},null,null,null);
LinearLayout artistLayout = (LinearLayout)view.findViewById(R.id.artistsAlbums);
for(albumsCursor.moveToFirst();!albumsCursor.isAfterLast();albumsCursor.moveToNext())
{
View albumView = LayoutInflater.from(view.getContext()).inflate(android.R.layout.simple_list_item_1,artistLayout,false);
((TextView)albumView.findViewById(android.R.id.text1)).setText(albumsCursor.getString(0));
artistLayout.addView(albumView);
}
Log.d("POPULATE","populated again!");
albumsCursor.close();
}
});
return view;
}
}
This works just fine. when i click an artist name, the linearlayout populates with all of this artist album names.
the problem is, that once a linearLayout scrolls out of view, it shows again from the other edge of the view (PacMan Style) as if another list item's linearLayout was populated.
It happens every time the expanded layout goes out of sight. the funny part is that some times when scrolling back up, the linearLayout shows under a different artist name.
example
I'll be glad to hear how should I implement this fragment. But i will also like to know why this behavior is caused.
Thanks,
Maor.
I have found the solution here at stackoverflow.com
It appears that the view shouldn't hold any data, since it is being used for different data when i scroll back and fourth.
I think holding an external data structure to save each virtual view state is not nice programming. is there a way to keep this data anyway? (for this i will be looking now)

Android ListView select items to delete with 3 column layout

I'd like to implement a Listview in android in which I have the possibility to enable a delete mode, in which the user can select the entries to delete. It should be similar to the message application in android.
I already have a ListActivity which has an icon on the left and text on the right side. I now like to add a CheckBox floating on the right side of the list entry. The ListActivity is listed in another question by a friend of mine: android listactivity background color .
The layout should be:
Left Picture
Center List item
Right Checkbox for delete selection
How can I achieve this? Is there a standard ListView item in the framework I could use?
I guess you want a CheckBox to appear(only) when is time to delete items from the ListView. Assuming you use the layout from the other question:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:background="#color/darkbluelogo" >
<ImageView android:id="#+id/list_image"
android:layout_width="48dip"
android:layout_height="48dip"
android:contentDescription="#id/list_image"
/>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="fill_parent"
android:padding="5dp"
android:background="#color/darkbluelogo"
android:scrollingCache="false"
android:cacheColorHint="#00000000" >
<TextView
android:id="#+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#+id/title" >
</TextView>
<TextView
android:id="#+id/datetime"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#+id/datetime" >
</TextView>
</LinearLayout>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
When the ListView starts the CheckBox will not be present and the content TextViews will occupy all the space. Add a flag in the getView method of your adapter that will signal that the CheckBox must be shown(here you will set the CheckBox's visibility from the layout to visible). When its time to delete items modify the flag and then call notifyDataSetChanged() so the ListView redraws its children, this time with the CheckBox present.
Note:
You'll have to store the status of the CheckBoxes yourself.
First of all you need a custom layout for your list entries. A simple RelativeLayout including an ImageView , a TextView and a CheckBox should be enough.
Then you might want to build your own custom adapter which can extend BaseAdapter (or SimpleAdapter or CursorAdapter or ArrayAdapter or...). The adapter will bind the list's data to your custom layout. If for example your data is contained in a Cursor it will look like:
private class MyCustomAdapter extends CursorAdapter {
public MyCustomAdapter(Context context) {
super(context, null);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
//Return a list item view
return getLayoutInflater().inflate(R.layout.my_custom_list_item_layout, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
//Get views from layout
final ImageView imageView = (ImageView) view.findViewById(R.id.list_item_image);
final TextView textView = (TextView) view.findViewById(R.id.list_item_text);
final CheckBox checkBox = (CheckBox) view.findViewById(R.id.list_item_checkbox);
//Get data from cursor
final String text = cursor.getString(...);
//Add listener to the checkbox
checkBox.setOnClickListener(new OnClickListener() {...});
//Bind data
textView.setText(text);
}
}

Add static header to listFragment in onCreateView

How can I add a simple static header to my listview inside a listFragment? I want to create the header from an xml def and add it through inflation.
My onCreateView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View detailList = inflater.inflate(R.layout.detail_fragment, container, false);
View detailListHeader = inflater.inflate(R.layout.daily_sales_header, null, false);
container.addView(detailListHeader, 0);
return detailList;
}
This creates the header, but it is not above the listview, rather the listview appears underneath the header, ie the header is overlaying the listview.
Any hints on the correct implementation?
Putting hackbod's description into code for you since his answer created more questions before the answers came. Sometimes I just want the fish. I don't always need to know how the net is made...
To start with, create a layout that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myListViewWithHeader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp"
android:textStyle="bold"
android:textSize="20sp" />
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false" />
<TextView
android:id="#android:id/empty"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Then, in your onCreateView method you do this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.myListViewWithHeader, null);
return view;
}
The header can now be populated by doing this:
// get the header view
TextView headerView = (TextView) getView().findViewById(R.id.header);
headerView.setText("Header text goes here");
Notice that my header is a TextView, but it can be replaced with another view if you like. In that case you will need to do a getView().findViewById(R.id.xxxxx) for each view inside the header you want to work with
You should NEVER EVER be adding views directly to the container in onCreateView(). Please read the documentation: http://developer.android.com/reference/android/app/Fragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
Also see the various sample code in the Fragment documentation, as well as the API demos: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/index.html
There is nothing special about using a Fragment here. Just build a view hierarchy containing a ListView like you normally would in an Activity or elsewhere. You always need to return one View from onCreateView; this is the root of your hierarchy.
For example you could make the ListView and then use this to add a header to it: http://developer.android.com/reference/android/widget/ListView.html#addHeaderView(android.view.View)

Categories

Resources