ListView - differentiate between a checkbox selection and a text selection - android

Given the ListView below, I wanted to perform two different actions depending on whether the user selects the text (create a new activity) or clicks the associated checkbox (add it to a favorites list). Is this possible in with this setup or will I have to use a custom adapter or even a different layout?
<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">
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice, teams));
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String team_name = adapterView.getItemAtPosition(i).toString().trim();
Intent intent = new Intent("blah.blah.blah");
intent.putExtra("team", team_name);
startActivity(intent);
}
});
A

If I am understanding you correctly, your ListView should contain TextBox and CheckBox and TextBox and CheckBox are clickable, not ListView itself.
For this you have to make custom adapter, where you will make listeners for both the TextBox and CheckBox.
public class CustomAdapter extends BaseAdapter {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// your_costum_view should contain textbox and checkboc
view = inflater.inflate(R.layout.your_costum_view, null);
// Get your checkbox and textbox and add listeners
TextView textView = (TextView) view.findById(R.id.textView);
textView.setOnClickListener...
Checkbox checkbox=(CheckBox)view.findById(R.id.checkBox);
checkBox.setOnClickListener...
return view;
}
}
your_costum_view layout example
<?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" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<CheckBox
android:id="#+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

Using a custom adapter will help you keep trace of your views, it will be easier than use a default adapter that you can't control. For references: http://www.vogella.com/tutorials/AndroidListView/article.html#adapterown_custom

Using a custom adapter will definitely make your life easier. In the adapter you can make reference to both the checkbox and the textView and add an onClick Listener to each - from there you can also add code to handle each event. I would also suggest using a recyclerView instead of a ListView. It is the new thing in Android 5.0 and it really is easier to use then a regular ListView. Hope this helps:
RecyclerView Help

Set the CheckBox as focusable="false" in your XML layout.
android:focusable="false"
if don't run go to this link and see example because you need a create custom row in list view and set:
Checkbox checkbox=(CheckBox)view.findById(R.id.checkboxID);
checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//do stuff
}
});

Related

Radio Button layout not appearing with listview/adapter in dialog

I'm fairly new to Android but am trying my hardest to get a handle on it. I've been researching this most of the day and I've concluded that there must be an issue with my actual adapter.
Unfortunately when I load up my dialog box I don't get the list view populating.
My Goal
I want to have a dialog that appears that is a custom layout that contains a listview. This has been created and has been demonstrated to work with other adapters. When the listview appears I want one option selected automatically with the radio buttons.
Custom Dialog XML
<?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"
android:background="#drawable/dialog_main_style">
<TextView
android:id="#+id/main_title_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingBottom="12dp"
android:paddingTop="12dp"
android:text="Format"
android:textColor="#020202"
android:textSize="20sp" />
<View
android:id="#+id/dialog_top_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="#+id/main_title_dialog"
android:layout_marginBottom="12dp"
android:background="#e4e4e4" />
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/format_choices_list_view"/>
<TextView
android:id="#+id/ok_change_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/dialog_gradient_button"
android:gravity="center"
android:layout_below="#id/dialog_top_divider"
android:padding="16dp"
android:text="OK"
android:textColor="#009261"
android:textStyle="bold" />
</LinearLayout>
Nothing special here, just a reference to my custom layout and my ListView.
Custom Listview for radio buttons
<?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">
<RadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/format_radio_button"
android:text="mp3"
android:button="#null"
android:drawableRight="#android:drawable/btn_radio"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp" />
</LinearLayout>
Normally radio buttons need a radio group but as it's a custom layout I want to use it seems like I'd only need 1 radio button?
Creating the Dialog and adapter
private void showFormatChangeDialog() {
//TODO get the list view working in the dialog
Dialog changeFormatDialog = new Dialog(SettingsActivity.this);
changeFormatDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
changeFormatDialog.setContentView(R.layout.change_audio_format_dialog);
changeFormatDialog.getWindow().getAttributes().width = WindowManager.LayoutParams.MATCH_PARENT;
ListView formatListView = (ListView) changeFormatDialog.findViewById(R.id.format_choices_list_view);
AudioFormatAdapter adapter = new AudioFormatAdapter(SettingsActivity.this);
formatListView.setAdapter(adapter);
changeFormatDialog.show();
}
I create a dialog and set it to my custom dialog layout. I then get a reference to my list view and crate an adapter and set it.
FormatAdapter
public class AudioFormatAdapter extends ArrayAdapter<String> {
static class ViewHolder {
RadioButton radioButton;
}
private String formatNames[] = {"mp3", "wav","amr"};
public AudioFormatAdapter(Context c) {
super(c, 0);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View formatView = convertView;
ViewHolder holder;
if(formatView == null) {
formatView = LayoutInflater.from(getContext()).inflate(R.layout.list_view_formats_layout, parent, false);
holder = new ViewHolder();
holder.radioButton = (RadioButton) formatView.findViewById(R.id.format_radio_button);
holder.radioButton.setText(formatNames[position]);
formatView.setTag(holder);
} else {
holder = (ViewHolder)formatView.getTag();
}
return formatView;
}
}
My goal here is to get a reference to my custom list view for the radio button. I grab a reference of the radio button and set the text to my array value based on the position.
I don't seem to get any data back from this ArrayAdapter and it's been blowing my mind. I've used several ArrayAdapter since I started and I haven't had this trouble. When I replaced this adapter with a different one it worked. I'm not sure what the issue is here.
Any help would be greatly appreciated.
Thank you.
Well it's fixed what I wanted and I think it came down to the adapter failing. Now I'm aware my adapter does not have a ViewHolder but it has a limit amount of options so it's ok for now.
First I needed a class that allowed a CheckableLinearLayout. This is a special type of LinearLayout that allows sections of the layout to be checked and unchecked. You simply make a new class of it and then add it to your XML file as the rootview. com.YOUR-IDENTIFIER-CLASS-NAME-OF-CHECKABLELINEARLAYOUT :) You can see it in the link below!
Checkable Linear Layout - Found here - How do a custom listview item with a radiobutton and single choice
After using that class I made a different adapter that was much simplier and it just seemed to work.
Adapter
public class AudioFormatAdapter extends ArrayAdapter<String> {
private ArrayList<String> formats;
public AudioFormatAdapter(Context c){
super(c, 0);
}
public AudioFormatAdapter(Context c, ArrayList<String> choices){
super(c, 0, choices);
formats = choices;
}
#Override
public View getView(final int position, final View convertView, ViewGroup parent) {
View listItemView = convertView;
listItemView = LayoutInflater.from(getContext()).inflate(R.layout.list_view_formats_layout, parent, false);
CheckedTextView _radioButton = (CheckedTextView) listItemView.findViewById(R.id.format_radio_button);
_radioButton.setText(formats.get(position));
return listItemView;
}
}
As we can see this adapter gets a "CheckedTextView" instead of the radio button. The reason for this is that I simply needed a radio button style with some text and this gives me that.
I set the text with an arrayList that I pass to the adapter in "formats"
Finally I create the Dialog and get a reference to my list view.
Dialog Creation with custom layout
private void showFormatChangeDialog(ArrayList<String> formatNames) {
LayoutInflater inflater = LayoutInflater.from(SettingsActivity.this);
View dialogLayout = inflater.inflate(R.layout.change_audio_format_dialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(SettingsActivity.this);
builder.setView(dialogLayout);
final ListView formatListView = (ListView) dialogLayout.findViewById(R.id.format_choices_list_view);
formatListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
final AudioFormatAdapter adapter = new AudioFormatAdapter(SettingsActivity.this, formatNames);
formatListView.setAdapter(adapter);
AlertDialog customDialog = builder.create();
customDialog.show();
}
If you only want one of the options selected then set the mode to SINGLE_CHOICE. I make the adapter here and pass in a list of strings which are accepted as a parameter to my function. Then the dialog is created
Conclusion
This was a rather irritating process as I think my adapter was breaking most things, I hope my trolling around the Internet and finding out bits and pieces can help someone else. Now I just need to save and store data depending on which option is selected!
I hope this helps somebody!

unable to select row in listview in a popup in 4.1 but working in android 5.0

I have a popup in my page which has a listview. I have created design of popup in a seperate xml and loading it on some button click in my main page. The popup has a listview with each row having a image and a textview. I am not able to get row selection in listview in android 4.1 but it is working in 5.0. Can anyone please suggest me the solution?
Listview:
<ListView android:id="#+id/lstSites"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fastScrollEnabled="true"
android:layout_margin="5dp"
android:descendantFocusability="blocksDescendants"></ListView>
</LinearLayout>
Listview Item:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:focusable="false"
android:focusableInTouchMode="false">
<ImageView
android:id="#+id/thumbImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:focusable="false"
android:focusableInTouchMode="false"/>
<TextView
android:id="#+id/tvSite"
android:textSize="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="Name"
android:focusable="false"
android:focusableInTouchMode="false"/>
adding row click listner:
lstSiteMenu = (ListView) popupView.findViewById(R.id.lstSites);
adapter = new MenuItemsAdapter(SiteActivity.this, arrMenu);
// Attach the adapter to a ListView
lstSiteMenu.setAdapter(adapter);
lstSiteMenu.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
final int position, long id) {
}
Try all of solutions:
popupwindow.setFocusale(true);
listView xml : "android:focusable="true"
do not use lstSiteMenu.setOnItemClickListener
instead go to your Adapters getView and add
convertView.setOnClickListener
Hope it will help you!
remove this property from listview , android:descendantFocusability="blocksDescendants"
and
android:focusable="false"
android:focusableInTouchMode="false"
from text and imageview.
And try This is sample example,
String names[] ={"A","B","C","D"};
AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.this);
LayoutInflater inflater = getLayoutInflater();
View convertView = (View) inflater.inflate(R.layout.row_file, null);
alertDialog.setView(convertView);
alertDialog.setTitle("List");
ListView lv = (ListView) convertView.findViewById(R.id.listView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,names);
lv.setAdapter(adapter);
alertDialog.show();
otherwise your code is fine. it works.
go through this link for more details.
Another official link for the same.
You need to remove android:descendantFocusability="blocksDescendants" from your ListView.
Also remove android:focusable="false" and android:focusableInTouchMode="false" from your row layout in the ImageView and the TextView.
The list item is supposed to be clickable, there is disable it obtaining focus
Set row onclick listener in adapter class
public class MenuItemsAdapter extends Base Adapter{
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
/*
Paste your adapter code
*/
customView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.v("log", "You clicked at pos "+position);
}
});
}
}
This code worked in all sdk versions.
Also remove these properties from xml files
android:descendantFocusability="blocksDescendants"
android:focusable="false"
android:focusableInTouchMode="false"

(Android) How do i access and modify a specific element in a custom listview, seeing as it uses a custom adapter?

I have a custom list view, here is its layout.xml
<?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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:id="#+id/playerToken"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/playerName"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/playerMoney"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
And here is the custom Adapter which takes an array of a Player Object which stores information like the players name, his token to represent him, and his money balance. the adapter takes that information and populates my custom list, as the layout above.
public class MyAdapter extends ArrayAdapter<Player> {
public MyAdapter(Context context, Player[] values) {
super(context, R.layout.activity_banking_layout, values);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater theInflater = LayoutInflater.from(getContext());
View theView = theInflater.inflate(R.layout.activity_banking_layout, parent, false);
Player player = getItem(position);
TextView playerNameText = (TextView) theView.findViewById(R.id.playerName);
TextView playerMoneyText = (TextView) theView.findViewById(R.id.playerMoney);
ImageView playerToken = (ImageView) theView.findViewById(R.id.playerToken);
playerNameText.setText(player.getName());
playerMoneyText.setText(Integer.toString(player.getMoney()));
int rId = theView.getResources().getIdentifier(player.getToken(), "drawable",
getContext().getPackageName());
playerToken.setImageResource(rId);
return theView;
}
}
This is just the layout showing the listView that us being adapted:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/bankListView" />
</LinearLayout>
So basically, my list is created and adapter in the onCreate method of the activity showing the list. After that my list items can open a context menu and depending on what is selected the player objects are manipulated. I want my list to reflect these changes, so i was wondering how i can access a specific part of my custom list and edit it. For example my custom list has a player icon, and to the right, the players name and below the name a money amount. Lets say i want to change the money amount of a specific player and reflect that change on the list, how do i access that specific TextView, within that specific position in that ListView ?
Since your adapter 'MyAdapter' extends ArrayAdapter, you can try using getItem(int position) which return the list item at the specified position; a Player object in your case. From there, you can modify your object's data member (amount of money) and then refresh the list to reflect your changes with notifyDataSetChanged().
In case you wanted to know the index/position of the clicked list item, then your question would be a duplicate of this one.
instead of manipulating the textview, consider the following approach:
make the Player[] array a global variable, instead of passing it to constructor,. then manipulate the Player object directly, then call
notifyDataSetChanged()
on your adapter which will automatically update your correct textview.
private Player[] values;
public void onCreate(Bundle s){
/*your onCreate things*/
MyAdapter adapter = new MyAdapter(this);
// update player 5 from array
values[4].money = newMoneyVal;
// after updating, call notifyDataSetChanged()
adapter.notifyDataSetChanged();
}
public class MyAdapter extends ArrayAdapter<Player> {
public MyAdapter(Context context) {
super(context, R.layout.activity_banking_layout, values);
}
/*rest of your adapter class*/
}
let me know if this works or if you have any questions
Yuo just have to implement a onlistitemclick listener, like this:
#Override
protected void onListItemClick(ListView l, View v, int pos, long id) {
super.onListItemClick(l, v, pos, id);
l[pos].findViewById(R.id.yourTagName).setText("ChangedValue");//to be adapted
}

check multiple items in list view

I use an adapter to load a list view from a content provider. Each item in the list uses the below layout.
<?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">
<LinearLayout
android:id ="#+id/wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckedTextView
android:id="#+id/txt_chat"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
/>
</LinearLayout>
</LinearLayout>
I have set the list item to allow multiple choice mode :
onCreate(){
...
lv_chatMessages = (ListView) findViewById(R.id.listview_chat);
lv_chatMessages.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
lv_chatMessages.setItemsCanFocus(false);
...
}
But at run time, i am not able to check any of the items in the list view. If i touch the box, the item just gets highlighted momentarily, but no check mark appears.
I can set a default for all the items if i add an attribute to the CheckedTextView :
android:checked="true"
How do i let the user change the check status of each item at runtime?
refer this link...
CheckedTextView
this may help you..
[Edit by Faizal] :
Using the toggle() inside the onItemClickListener did the trick :
lv_chatMessages.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3){
CheckedTextView ctv = (CheckedTextView) (((ViewGroup) arg1).findViewById(R.id.txt_chat));
ctv.toggle();
}
});
can you add this into list items
android:descendantFocusability="blocksDescendants"
android:focusableInTouchMode="false"
Since, you are using a custom adapter, you'll have to maintain the status of the checkbox in the getView() method of the custom adapter.
What you could probably do is to add another Boolean field to your ArrayList of Objects which you use to populate the adapter and check that value in the getView() method. to Something like :
if(status) {
checkBox.setChecked(true);
}
Also, update the status variable using OnCheckedChangeListener().
This method will let you toggle status and also ensure that the checkbox status is maintained even when a list item goes out of the view.
Edit 1 : When not using a custom adapter. This is how I did it.
ListView rendererList;
ArrayList<String> friendlyNames;
friendlyNames = new ArrayList<String>();
rendererList = (ListView) dialog.findViewById(R.id.rendererList);
ArrayAdapter rendererSelectionAdapter = new ArrayAdapter<String>(activity,R.layout.custom_list_layout, friendlyNames);
rendererList.setAdapter(rendererSelectionAdapter);
rendererList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
custom_list_layout was the same layout which android provides, however, I had to make slight modifications so I copied the default file and edited.
here is the custom_list_layout :
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:background="#color/white"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:gravity="center_vertical"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:textSize="#dimen/dialog_box_button_textsize" />

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" />

Categories

Resources