Using a custom ListPreference, I'm trying to ask the user to choose between 2 pre-defined values, and a custom value he can set using an edittext.
Everything seems to work, except that the keyboard doesn't show up when I click on the EditText.
However, the EditText seems to gain focus, as it would normally.
Here is the image of what I'm obtaining (see the focus seems to be alright)
https://www.dropbox.com/s/isejjkveonwnb3f/Screenshot_2013-05-30-21-43-41.png
Here is the layout of the custom list preference row:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingBottom="8dip"
android:paddingTop="8dip"
android:paddingLeft="10dip"
android:paddingRight="10dip">
<EditText
android:id="#+id/ET_prefs_customText"
android:layout_width="0dip"
android:layout_weight="1"
android:hint="#string/SP_address_hint"
android:layout_height="wrap_content"
/>
<RadioButton
android:id="#+id/custom_list_view_row_radio_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false" />
</LinearLayout>
And here is my CustomListPreference code:
public class CustomListPreference extends ListPreference
{
/*
* removed useless stuff
*/
#Override
protected void onPrepareDialogBuilder(Builder builder)
{
entries = getEntries();
entryValues = getEntryValues();
if (entries == null || entryValues == null || entries.length != entryValues.length )
{
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array which are both the same length");
}
customListPreferenceAdapter = new CustomListPreferenceAdapter(mContext);
builder.setAdapter(customListPreferenceAdapter, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
}
});
}
private class CustomListPreferenceAdapter extends BaseAdapter
{
private SharedPreferences prefs;
public CustomListPreferenceAdapter(Context context)
{
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
}
/*
* removed usual adapter stuff (getCount, getItem...)
*/
public View getView(final int position, View convertView, ViewGroup parent)
{
View row = convertView;
if(row == null)
{
//If it's not the last one: use a normal holder...
if(position < 2)
{
NormalHolder holder = null;
row = mInflater.inflate(R.layout.normal_list_preference_row, parent, false);
if(prefs.getString(mContext.getString(R.string.SP_address), "0").equals(entryValues[position])) {
holder = new NormalHolder(row, position,true);
} else {
holder = new NormalHolder(row, position,false);
}
row.setTag(holder);
row.setClickable(true);
row.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
for(RadioButton rb : rButtonList)
{
if(rb.getId() != position)
rb.setChecked(false);
}
int index = position;
String value = entryValues[index].toString();
Log.v("Editor", "putting string" + value);
editor.putString(mContext.getString(R.string.SP_address), value);
editor.commit();
Dialog mDialog = getDialog();
mDialog.dismiss();
}
});
//Otherwise, if it is the last one...
} else {
//Use the custom row
row = mInflater.inflate(R.layout.custom_list_preference_row, parent, false);
String fromPref = prefs.getString(mContext.getString(R.string.SP_address), "0");
boolean flag=false;
for(CharSequence entry : entryValues) {
if(entry.toString().equals(fromPref)) {
flag=true;
}
}
//And use a "custom holder"
CustomHolder holder;
if(!flag) {
holder = new CustomHolder(row, position, fromPref, true);
} else {
holder = new CustomHolder(row, position, "", false);
}
row.setTag(holder);
}
}
return row;
}
/*
* This class just shows the information in row from the position and the PreferenceList entries
*/
class NormalHolder
{
private TextView text = null;
private RadioButton rButton = null;
NormalHolder(View row, int position, boolean isCheked)
{
text = (TextView)row.findViewById(R.id.custom_list_view_row_text_view);
text.setText(entries[position]);
rButton = (RadioButton)row.findViewById(R.id.custom_list_view_row_radio_button);
rButton.setId(position);
rButton.setChecked(isCheked);
// also need to do something to check your preference and set the right button as checked
rButtonList.add(rButton);
rButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if(isChecked)
{
/*
* Put stuff into SharedPreference
*/
}
}
});
}
}
/*
* This class display the text within the EditText
*/
class CustomHolder
{
private EditText text = null;
private RadioButton rButton = null;
CustomHolder(View row, int position, String pref, boolean checked)
{
text = (EditText)row.findViewById(R.id.ET_prefs_customText);
text.setText(pref);
rButton = (RadioButton)row.findViewById(R.id.custom_list_view_row_radio_button);
rButton.setId(position);
rButton.setChecked(checked);
rButtonList.add(rButton);
rButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if(isChecked)
{
/*
* Put stuff into SharedPreference
*/
}
}
});
}
}
}
}
Note that this was based on another answered found here: custom row in a listPreference?
Edit: I've added a few code above (see onPrepareDialogBuilder), because it might come from the Dialog built.
Ok, I managed to solve this out.
As said here: https://stackoverflow.com/a/9118027/1376834
The problem seems to be (at least in my case), that since the place where you enter text is hidden initially (or nested or something), AlertDialog is automatically setting the flag WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM (or some combination of that and WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) so that things don't trigger a soft input to show up.
So I just added
getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
in my CustomHolder constructor, so that the Dialog is already built when I do so.
Related
I'm using RecyclerView with select all option.this option select screen visible items only. Not all select. But I scroll top to bottom after selected. what is the problem?
Adapter class:
public class FilterBrandAdapter extends RecyclerView.Adapter<FilterBrandAdapter.MyViewHolder> {
private ArrayList<FilterBrandDataModel> mBrandModelArraylist;
private Context mContext;
private TinyDB mPrefDb;
private boolean isSelectedAll;
public static final String PREF_SELECTED_ALL = "selectedAll";
private CartTotalListener mCartListener;
public void selectAll() {
Log.e("onClickSelectAll", "yes");
isSelectedAll = true;
notifyDataSetChanged();
}
public void deselectAll() {
Log.e("onClickSelectAll", "no");
isSelectedAll = false;
notifyDataSetChanged();
}
class MyViewHolder extends RecyclerView.ViewHolder {
CheckBox cbItemTitle;
MyViewHolder(View itemView) {
super(itemView);
cbItemTitle = (CheckBox) itemView.findViewById(R.id.checkBox_filter_brand_title);
itemView.setClickable(true);
}
}
public FilterBrandAdapter(BrandFilterActivity activity, ArrayList<FilterBrandDataModel> mArrayList) {
this.mContext = activity;
this.mBrandModelArraylist = mArrayList;
LayoutInflater inflater = activity.getLayoutInflater();
try {
this.mCartListener = ((CartTotalListener) mContext);
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement AdapterCallback.");
}
}
#Override
public FilterBrandAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_recycler_brand_items, parent, false);
mPrefDb = new TinyDB(mContext);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final FilterBrandDataModel brandsData = mBrandModelArraylist.get(position);
holder.cbItemTitle.setText(mBrandModelArraylist.get(position).getCategoryName());
//set adapter classcheckbox change listener for if clicked or not
holder.cbItemTitle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (holder.cbItemTitle.isChecked()) {
//if check box checked selected checkbox saved in tinyDB
int getPosition = (int) buttonView.getTag();
mBrandModelArraylist.get(getPosition).setSelected(buttonView.isChecked());
mPrefDb.putBoolean(brandsData.getCategoryName(), true);
holder.cbItemTitle.setChecked(true);
Log.e("checked item-->", brandsData.getCategoryName());
mCartListener.onMethodCallback();
} else {
//else check box un-checked selected checkbox save checkbox is un-checked in tinyDB
int getPosition = (int) buttonView.getTag();
mBrandModelArraylist.get(getPosition).setSelected(buttonView.isChecked());
mPrefDb.putBoolean(brandsData.getCategoryName(), false);
holder.cbItemTitle.setChecked(false);
Log.e("un-checked item-->", brandsData.getCategoryName());
mCartListener.onMethodCallback();
}
}
});
//select & deselect all checkbox in recyclerview
if (!isSelectedAll) {
holder.cbItemTitle.setTag(position);
holder.cbItemTitle.setChecked(mBrandModelArraylist.get(position).isSelected());
holder.cbItemTitle.setChecked(false);
} else {
holder.cbItemTitle.setTag(position);
holder.cbItemTitle.setChecked(mBrandModelArraylist.get(position).isSelected());
holder.cbItemTitle.setChecked(true);
}
//save selected (or) deselect checkbox with position in tinyDB
holder.cbItemTitle.setTag(position);
holder.cbItemTitle.setChecked(mBrandModelArraylist.get(position).isSelected());
boolean checked = mPrefDb.getBoolean(brandsData.getCategoryName(), true);
holder.cbItemTitle.setChecked(checked);
}
#Override
public int getItemCount() {
return mBrandModelArraylist.size();
}
}
I use interface(mCartListener.onMethodCallback()) for notify selected items & display items counts in text view.
my interface:
#Override
public void onMethodCallback() {
ArrayList<String> array = new ArrayList<>();
//checking which items are selected in adapter class & save into array list
for (FilterBrandDataModel brandDataModel : mArrayList) {
if (brandDataModel.isSelected()) {
array.add(brandDataModel.getCategoryName());
}
}
int size = array.size();
if (size == mArrayList.size()) {
mPrefDb.putString(PREF_SELECTED_BRANDS_TOT, "true");
String text = String.valueOf(size) + " " + getResources().getString(R.string.msg_selected);
mBrandResults.setText(text);
} else {
mPrefDb.putString(PREF_SELECTED_BRANDS_TOT, "false");
String text = String.valueOf(size) + " " + getResources().getString(R.string.msg_selected);
mBrandResults.setText(text);
}
}
RecyclerView loads the data while scrolling, but I need all data in it without scrolling. So, I changed the RecyclerView in ScrollView like that:
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.85"
android:overScrollMode="never"
android:scrollbars="none">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
/>
</ScrollView>
then, in the Activity,
RecyclerView.setNestedScrollEnabled(false);
I use the ScrollView to scroll items. That's it.
The problem is that you only switch a flag in selectAll() (isSelectedAll = true;). In your adapter there will be for example 3 visible items (i don't know how big they are at your screen). One item is represented by one viewholder. After you switch the flag and call notifyDataSetChanged() the function onBindViewHolder() will be called for every visible item -> in my example 3 times. In this function you decide with if (!isSelectedAll) { if the checkbox should be selected. So it will never be called for all items.
Solution:
Change
public void selectAll() {
Log.e("onClickSelectAll", "yes");
isSelectedAll = true;
notifyDataSetChanged();
}
To
public void selectAll() {
Log.e("onClickSelectAll", "yes");
for(FilterBrandDataModel brandsData : mBrandModelArraylist) {
mPrefDb.putBoolean(brandsData.getCategoryName(), true);
}
notifyDataSetChanged();
}
And the same for deselectAll().
I am trying to load a list in RecyclerView and show the first row of the list as selected. I have achieved it using the following code:
#Override
public void onBindViewHolder(NavigationDrawerAdapter.ViewHolder holder, final int position) {
if (!mNavClassrooms.get(position).equals("")) {
holder.mTextViewClassroom.setText(mNavClassrooms.get(position)); // Setting the Text with the array of our Titles
holder.mRelLayClassroom.setSelected(mSelectedItems.get(position, false));
/*
The following code was written to make the first item in the Classroom list as selected.
It leads to the item always being selected and hence has been commented out.
*/
if(position == 0 && intOldSelectedItem == -1){
holder.mRelLayClassroom.setSelected(mSelectedItems.get(position, true));
intOldSelectedItem = 0;
mSelectedView = holder.mRelLayClassroom.getChildAt(position);
mSelectedItems.put(position, true);
}
else{
holder.mRelLayClassroom.setSelected(mSelectedItems.get(position, false));
}
} else {
holder.mTextViewClassroom.setText("No classes found");
holder.mTextViewClassroom.setPadding(40, 0, 0, 0);
}
holder.mRelLayClassroom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mSharedPreferences = mContext.getSharedPreferences(Constants.AAPREFERENCES, Context.MODE_PRIVATE);
String strClassroomValue = mNavClassrooms.get(position);
int strClassroomName = mNavClassroomNames.get(position);
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(Constants.CLASSROOM_VALUE, strClassroomValue);
editor.putInt(Constants.CLASSROOM_NAME, strClassroomName);
editor.commit();
/*
We are storing the position of the selected row in the SparseBooleanArray.
We delete it in case another row has been selected.
*/
if (mSelectedItems.get(position, false)) {
/*
Do nothing
*/
} else {
mSelectedItems.put(position, true);
/*
Making sure that the delete code is called only if some view is selected
*/
if (mSelectedView != null) {
mSelectedView.setSelected(false);
mSelectedItems.delete(intOldSelectedItem);
view.setSelected(false);
}
mSelectedView = view;
intOldSelectedItem = position;
view.setSelected(true);
}
}
However, now the first row stays selected always. I am unable to deselect it. I cannot seem to get this working.
I referred to the following answer to achieve most of this functionlaity.
https://stackoverflow.com/a/29984220/2186220
Any help will be appreciated.
I'm not answering your question by posting a fixed version of your onBindViewHolder method since it's kinda hard to understand and we don't know how the rest of your adapter looks like. So following a RecyclerView Adapter which does what you want: Selecting the first row by default and deselecting it once a other row is selected.
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
// ... other fields
// default selection position is the first one
private int selectedPosition = 0;
// ... constructor etc.
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
if(position == selectedPosition){
holder.itemView.setSelected(true);
} else {
holder.itemView.setSelected(false);
}
// Actual selection / deselection logic
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int currentPosition = holder.getLayoutPosition();
if(selectedPosition != currentPosition){
// Temporarily save the last selected position
int lastSelectedPosition = selectedPosition;
// Save the new selected position
selectedPosition = currentPosition;
// update the previous selected row
notifyItemChanged(lastSelectedPosition);
// select the clicked row
holder.itemView.setSelected(true);
}
}
});
// other adapter code
}
// other adapter stuff like onCreateViewHolder, getItemCount, ViewHolder etc.
}
Note: I guess there's no need to use a SparseBooleanArray so simply remove it and replace it with the int field used in the example above.
Initialize your
int intOldSelectedItem=0 and keep one boolean isVisible= false;
And do it as below:
if (holder.getPosition() == intOldSelectedItem) {
if (isVisible) {
//background for selected item
} else {
//background for unselected item
}
} else {
//background for unselected item
}
holder.mRelLayClassroom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (intOldSelectedItem== holder.getPosition()) {
isVisible = !isVisible;
} else {
if (intOldSelectedItem!= 0) {
isVisible = false;
notifyItemChanged(intOldSelectedItem);
}
isVisible = true;
}
intOldSelectedItem= holder.getPosition();
notifyItemChanged(intOldSelectedItem);
}
});
I hope it might help you.
Add background selector to your ViewHolder layout.
Create your selector handler something like this:
public class SingleSelector {
private View oldVIew;
public void setSelection(View newView) {
if (oldVIew == null) {
newView.setSelected(true);
oldVIew = newView;
} else {
oldVIew.setSelected(false);
newView.setSelected(true);
oldVIew = newView;
}
}
}
Set default selection when you need it:
#Override
public void onBindViewHolder(SimpleViewHolder holder, int position) {
if (position == 0) {
singleSelector.setSelection(holder.itemView);
}
}
In your ViewHolder add listener to itemView and pass it to the handler:
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
singleSelector.setSelection(itemView);
}
});
There seems to be a problem when there are more than 5 records to
display on Manage Practice. For e.g. if there are 6 records to display on
Manage Practice. If I check the check box number 1, the check box number 6 also
gets checked. If there are 7 records, and if I check on 2nd record, then
the 7th record also gets automatically checked.I don't what's going on there I am very confusing, Please check my code let me know what's problem is there.
public class ManagePracticeLogAdapter extends BaseAdapter
{
//Variables to save class object.
Context context;
// variable to instantiates a layout XML file into its corresponding View objects.
LayoutInflater inflater;
MenuItem menu,addlog;
List<Integer> SelectedBox= new ArrayList<Integer>();;
// Variable to accept list data from Produce log activity
ArrayList<HashMap<String, String>> data;
ArrayList<HashMap<String, String>> temp_data;
HashMap<String, String> resultp = new HashMap<String, String>();
List<String> deleteData=new ArrayList<String>();
// Constructor to accept class instance and data.
public ManagePracticeLogAdapter(Context context,
ArrayList<HashMap<String, String>> arraylist,MenuItem mymenu,MenuItem myaddlog)
{
this.context = context;
data = arraylist;
//temp_data.addAll(data);
menu=mymenu;
addlog=myaddlog;
}
#Override
public int getCount()
{
return data.size();
}
#Override
public Object getItem(int position)
{
return null;
}
#Override
public long getItemId(int position)
{
return 0;
}
// Method to display data of Produce log Activity in list view
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
if(convertView==null)
{
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView= inflater.inflate(R.layout.logitem1, parent, false);
}
TextView datetime;
TextView totminutes;
TextView skills;
TextView weather;
TextView day_night_icon;
final CheckBox chkdelete;
TextView approval_icon;
// Get the position
resultp = data.get(position);
// Locate the TextViews in listview_item.xml
datetime = (TextView) convertView.findViewById(R.id.id_datetime);
totminutes = (TextView) convertView.findViewById(R.id.totminutes);
skills= (TextView) convertView.findViewById(R.id.id_skills);
weather=(TextView)convertView.findViewById(R.id.id_weather);
day_night_icon=(TextView)convertView.findViewById(R.id.day_night_icon);
approval_icon=(TextView)convertView.findViewById(R.id.conditions);
chkdelete=(CheckBox)convertView.findViewById(R.id.id_chkDelete);
// Capture position and set results to the TextViews
datetime.setText(resultp.get("date_time"));
if(!resultp.get("Day_minutes").toString().equalsIgnoreCase("0"))
{
totminutes.setText(resultp.get("Day_minutes")+" min");
day_night_icon.setBackgroundResource(R.drawable.sun);
}else
{
totminutes.setText(resultp.get("Night_minutes")+" min");
day_night_icon.setBackgroundResource(R.drawable.moon);
}
skills.setText(resultp.get("Skill"));
weather.setText(resultp.get("weather"));
String supervisorText=resultp.get("super");
Log.w("SUPERVISOR", supervisorText);
if(supervisorText.equals("No supervisor"))
{
approval_icon.setBackgroundResource(R.drawable.pending);
}else
{
approval_icon.setBackgroundResource(R.drawable.approve);
}
String fontPath = "fonts/Roboto-Light.ttf";
Typeface tf = Typeface.createFromAsset(context.getAssets(), fontPath);
datetime.setTypeface(tf);
totminutes.setTypeface(tf);
skills.setTypeface(tf);
weather.setTypeface(tf);
// chkdelete.setTag(R.id.id_chkDelete);
chkdelete.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
// int checkBoxId = (Integer) buttonView.getTag();
if(SelectedBox.size()-1==0)
{
menu.setVisible(false);
addlog.setVisible(true);
}else
{
addlog.setVisible(false);
}
if(isChecked)
{
SelectedBox.add(position);
menu.setVisible(true);
addlog.setVisible(false);
}else /*if(!isChecked)*/
{
SelectedBox.remove(SelectedBox.indexOf(position));
}
}
});
menu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// TODO Auto-generated method stub
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
// set title
alertDialogBuilder.setTitle("Student Driving Practice Log");
// set dialog message
alertDialogBuilder
.setMessage("Are you sure want to Delete Record!")
.setCancelable(false)
.setPositiveButton("Yes",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
try
{
NewNewDataHelper db=new NewNewDataHelper(context);
if(!SelectedBox.isEmpty())
{
for(int i=0;i<SelectedBox.size();i++)
{
resultp=data.get(SelectedBox.get(i));
String str[]=resultp.get("date_time").split(" ");
Log.d("Checked Element",str[0]+"\n"+str[1]+"\n"+resultp.get("Skill"));
db.DeleteSingleLog(resultp.get("Skill"),str[0],str[1]);
/*resultp=data.get(SelectedBox.get(i));
String str[]=resultp.get("date_time").split(" ");
db.DeleteSingleLog(resultp.get("Skill"),str[0],str[1]);*/
Toast.makeText(context,"Record Deleted", Toast.LENGTH_LONG).show();
}
Log.d("LISTSTSTSTST", SelectedBox.toString());
Intent intent = new Intent(context,ManagePracticeLogActivity.class);
intent.putExtra("s11", "delete");
context.startActivity(intent);
}
}catch(Exception e)
{
}
}
})
.setNegativeButton("No",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
return false;
}
});
convertView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View arg0)
{
resultp = data.get(position);
String str1 = null;
String str[]=resultp.get("date_time").toString().split(" ");
str1=str[0]+"~"+resultp.get("Skill")+"~"+str[1];
Log.d("PARTICULAR SKILLLLL", str1);
Intent intent = new Intent(context,LogEdit.class);
intent.putExtra("s11","Update Practice");
intent.putExtra("dataupdate",str1);
context.startActivity(intent);
}
});
return convertView;
}
private void deleteItems(List<Integer> list)
{
data.clear();
}
}
The problem is, view gets recycled due to recycling of ListView and the value of Checkbox(check or uncheck) is not maintained. You can check this link.
just have a look at this. This will explain the "problem" with checkboxes in listviews. There's also a link with a solution, if needed :)
When you load the view in getView, you need to set the check state for that particular item. I assume for each row you store this information somewhere? Just retrieve the correct state for the row (position) and set the correct state on the checkbox. The reason why you are seeing the behavior is because in a ListView rows are reused. The 6th row is in fact the 1st row. It is done this way to conserve memory and optimize a ListView for speed.
Inside your getView() add :
if(SelectedBox.contains(new Integer(position))) {
chkdelete.setChecked(true);
} else {
chkdelete.setChecked(false);
}
I've just gotten an ExpandableListView setup and everything works fine so far. On the group/parent I have a TextView and and Button. The purpose of the list is to have people sample different sounds that are included in the app, and it they click the button then the sounds will be saved to the SD Card. Here's a link to what I have so far: http://imgur.com/djSCIrG
My question is whether or not it's possible that after someone clicks the button and chooses to purchase the pack if it's possible to hide just that one button and not all of the buttons in every group.
Here's is my main layout (expandablelistview_main.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="#+id/soundpacktitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/expandablelistview_main_soundpacktitle_topmargin"
android:layout_centerHorizontal="true"
android:text="#string/soundpacktitle"
android:textSize="#dimen/expandablelistview_main_soundpacktitle_textsize" />
<ExpandableListView
android:id="#+id/soundpacklist"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_below="#+id/soundpacktitle"
android:layout_above="#+id/soundpackbottombar"
android:layout_marginTop="#dimen/expandablelistview_main_soundpacklist_topmargin"
android:transcriptMode="disabled"
android:cacheColorHint="#00000000"
android:listSelector="#android:color/transparent" />
</RelativeLayout>
Here is my group/parent layout (expandablelistview_group.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:orientation="horizontal" >
<TextView
android:id="#+id/grouptextview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_marginLeft="#dimen/expandablelistview_group_grouptextview_leftmargin"
android:textSize="#dimen/expandablelistview_group_grouptextview_textsize" />
<Button
android:id="#+id/buypackbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_alignParentRight="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="#string/buypack"
android:padding="#dimen/expandablelistview_group_buypackbutton_padding"
android:textSize="#dimen/expandablelistview_group_buypackbutton_textsize"
android:textStyle="bold" />
</RelativeLayout>
Here is my java class:
public class InAppSounds extends Activity {
private ExpandableListView soundpacklist;
private ArrayList<String> groups;
private ArrayList<ArrayList<ArrayList<String>>> childs;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.expandablelistview_main);
TextView soundpacktitle = (TextView) findViewById(R.id.soundpacktitle);
soundpacktitle.setTypeface(printbold);
// Declare the ExpandableListView and set's the indicator to the list arrows
soundpacklist = (ExpandableListView) findViewById(R.id.soundpacklist);
soundpacklist.setGroupIndicator(getResources().getDrawable(R.drawable.list_groupselector));
LoadData();
myExpandableAdapter adapter = new myExpandableAdapter(this, groups, childs);
soundpacklist.setAdapter(adapter);
}
// Loads the ExpandableListView with parent and children groups
private void LoadData() {
groups = new ArrayList<String>();
childs = new ArrayList<ArrayList<ArrayList<String>>>();
// String array that stores the parent and child names
String[] soundpackgroups = getResources().getStringArray(R.array.soundpackgroups);
String[] soundpack1 = getResources().getStringArray(R.array.soundpack1);
String[] soundpack2 = getResources().getStringArray(R.array.soundpack2);
String[] soundpack3 = getResources().getStringArray(R.array.soundpack3);
// First Sound Pack and their songs
groups.add(soundpackgroups[0]);
childs.add(new ArrayList<ArrayList<String>>());
for (int a = 0; a < soundpack1.length; a++) {
childs.get(0).add(new ArrayList<String>());
childs.get(0).get(a).add(soundpack1[a]);
}
// Second Sound Pack and their songs
groups.add(soundpackgroups[1]);
childs.add(new ArrayList<ArrayList<String>>());
for (int a = 0; a < soundpack2.length; a++) {
childs.get(1).add(new ArrayList<String>());
childs.get(1).get(a).add(soundpack2[a]);
}
// Third Sound Pack and their songs
groups.add(soundpackgroups[2]);
childs.add(new ArrayList<ArrayList<String>>());
for (int a = 0; a < soundpack3.length; a++) {
childs.get(2).add(new ArrayList<String>());
childs.get(2).get(a).add(soundpack3[a]);
}
}
public class myExpandableAdapter extends BaseExpandableListAdapter {
private final ArrayList<String> groups;
private final ArrayList<ArrayList<ArrayList<String>>> children;
private final Context context;
public myExpandableAdapter(Context context, ArrayList<String> groups,
ArrayList<ArrayList<ArrayList<String>>> children) {
this.context = context;
this.groups = groups;
this.children = childs;
}
#Override
public boolean areAllItemsEnabled() {
return true;
}
#Override
public ArrayList<String> getChild(int groupPosition, int childPosition) {
return children.get(groupPosition).get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
String child = getChild(groupPosition, childPosition).get(0);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.expandablelistview_child, null);
}
// TypeFace variable for the PrintBold
printbold = Typeface.createFromAsset(getAssets(), "fonts/PrintBold.otf");
TextView childtxt = (TextView) convertView.findViewById(R.id.childtextview);
childtxt.setTypeface(printbold);
childtxt.setText(child);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return children.get(groupPosition).size();
}
#Override
public String getGroup(int groupPosition) {
return groups.get(groupPosition);
}
#Override
public int getGroupCount() {
return groups.size();
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
final String group = getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.expandablelistview_group, null);
}
// TypeFace variable for the PrintBold
printbold = Typeface.createFromAsset(getAssets(), "fonts/PrintBold.otf");
TextView grouptxt = (TextView) convertView.findViewById(R.id.grouptextview);
grouptxt.setTypeface(printbold);
grouptxt.setText(group);
final Button buypackbutton = (Button) convertView.findViewById(R.id.buypackbutton);
buypackbutton.setClickable(true);
buypackbutton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
AlertDialog.Builder alert = new AlertDialog.Builder(InAppSounds.this);
if (group.equals("Pack #1")) {
alert.setCancelable(false);
alert.setTitle(getString(R.string.buypacktitle));
alert.setIcon(getResources().getDrawable(R.drawable.ic_audioicon));
alert.setMessage(getString(R.string.buypackmsg));
alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// check to make sure the SD card is mounted
// if not display an AlertDialog
if (!isSDPresent()) {
sdcardalert();
}
else {
// this will erase the button in all the groups, not just this group
buypackbutton.setVisibility(View.INVISIBLE);
}
}
});
alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alert.show();
}
}
});
return convertView;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
}
I would appreciate any guidance in this matter. Thanks
Yes. It's easy. All that you have to do is get a reference to your button and set the visibility to gone. Like this:
Button sampleButton = (Button) findViewById(R.id.sample_button);
sampleButton.setVisiblity(View.GONE);
Note: when you set it to View.GONE the layout space that was initially given to it is also removed. If you just want to remove the button and keep the layout space use
View.INVISIBLE instead.
EDIT: Here's how I would keep the button from reappearing: First, I would use a boolean to track the status of the button while the activity is active. Then in your override of getChildView I would check this boolean and set the visibility accordingly. Maybe insert something like this into the getChildView callback to keep the button from reappearing when the list item is clicked:
if (!showButton) {
Button button = (Button) findViewById(R.id.sample_button);
button.setVisibility(View.GONE);
}
As for coming back to the screen. To keep track of the whether not to show the button I would use a boolean and store it in SharedPreferences. Then, also in the getChildView callback, check the status of the boolean and set it accordingly. Something like this:
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean showButtonStatusPref = settings.getBoolean("showButton", true);
if(!showButtonStatusPref) {
Button button = (Button) findViewById(R.id.sample_button);
button.setVisibility(View.GONE);
}
The only other thing you need to do is manage the status of each button.
EDIT 2: I completely overlooked the fact that the same layout is used for the child views (duh! brain cramp :)).
You could still use shared preferences to keep track of which samples have been downloaded (you could use Set for this). You would also need to create a way to assign "identifiers" to each sample. From there all that you would have to do is perform a check every time getChildView() is called and, if the Set contains the selected sample identifier, set the button visibility to gone. That should take care of showing the button when the sample hasn't been downloaded and not showing the button when the sample has been downloaded. Maybe something like this in the getChildView():
Set<String> defaultSet = new SortedSet<String>();
defaultSet.add("Nothing downloaded");
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SortedSet<String> listOfDowloaded = settings.getStringSet("isDownloadedList", );
if (listOfDownLoaded.contains(sampleDownloadIdentifier)) {
Button button = (Button) findViewById(R.id.some_id);
button.setVisiblity(View.GONE);
}
I have an activity which extends ListActivity. It has many things but amongst them it shows the articles the user has purchased with an adapter. Well I have a method that the user can delete the items from the list. The problem is when there is only one item. If I try to delete the last one the app crashes. Here is a it of my code:
public class Ventas extends ListActivity {
......
lv = getListView();
......
protected void confirmRemoval(final int arg2) {
// TODO Auto-generated method stub
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle(getResources().getString(R.string.ventas));
alertDialog.setMessage(getResources().getString(R.string.confirmacion2));
alertDialog.setButton("Si",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if(adapter2.mEvents.size()>=1){
adapter2.mEvents.remove(arg2);
} else {
//doesn't work
/*adapter2=null;
adapter2.notifyDataSetInvalidated();
lv.setVisibility(View.GONE);*/
}
}
});
alertDialog.setButton2("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
alertDialog.show();
}
here is the adapter and wrapper:
private class EventAdapter2 extends BaseAdapter {
public ArrayList<Articulo> mEvents = null;
public EventAdapter2(Context c, ArrayList<Articulo> clientes) {
mContext = c;
mEvents = clientes;
}
public int getCount() {
return mEvents.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
EventEntryView2 btv;
if (convertView == null) {
btv = new EventEntryView2(mContext, mEvents.get(position));
} else {
btv = (EventEntryView2) convertView;
String title1 = mEvents.get(position).getCantidad() + "";
if (title1 != null) {
btv.setText1Title(title1);
}
String title2 = mEvents.get(position).getDescripcion();
if (title2 != null) {
btv.setText2Title(title2);
}
String title3 = mEvents.get(position).getpVenta() + "0";
if (title3 != null) {
btv.setText3Title(title3);
}
String title4 = (mEvents.get(position).getCantidad() * mEvents
.get(position).getpVenta()) + "0";
if (title4 != null) {
btv.setText4Title(title4);
}
}
return btv;
}
private Context mContext;
}
private class EventEntryView2 extends LinearLayout {
private TextView text1;
private TextView text2;
private TextView text3;
private TextView text4;
private View inflatedView;
public EventEntryView2(Context context, Articulo resp) {
super(context);
this.setOrientation(VERTICAL);
inflatedView = View.inflate(context, R.layout.results, null);
text1 = (TextView) inflatedView.findViewById(R.id.textView1);
text2 = (TextView) inflatedView.findViewById(R.id.textView2);
text3 = (TextView) inflatedView.findViewById(R.id.textView3);
text4 = (TextView) inflatedView.findViewById(R.id.textView4);
String t = resp.getCantidad() + "";
text1.setText(t);
String t1 = resp.getDescripcion();
text2.setText(t1);
String t2 = resp.getpVenta() + "0";
text3.setText(t2);
String t3 = (resp.getCantidad() * resp.getpVenta()) + "0";
text4.setText(t3);
addView(inflatedView, new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
public void setText4Title(String title4) {
text4.setText(title4);
}
public void setText3Title(String title3) {
text3.setText(title3);
}
public void setText2Title(String title2) {
text2.setText(title2);
}
public void setText1Title(String title1) {
text1.setText(title1);
}
}
as you can see when I have only one item left I have tried to set adapter to null or adapter.notifyDataSetInvaliadted or even making the listview invisible, nothing works. What happens is when I click ok nothing changes then when I click a second time it all crashes
What I would like is the listView to disappear when the adapter is empty but I am now out of ideas, is it even possible?
Any ideas?
EDIT:
Thank you all for the answers but the problem was I was modifying the list from inside an inner anonymous class. It is actually pretty simple, create a method and call it from inside the dialog, once the array is empty the list disappears automatically:
protected void removeFromList(int arg2) {
adapter2.mEvents.remove(arg2);
adapter2.notifyDataSetChanged();
}
remove item from the arraylist which you add into the adapter and then call this method.
youradapter.notifyDataSetChanged();
and whatever you do for single item that was
adapter2 = null;
adapter2.notifyDataSetInavlidated();
this will obviously crash it because adapter2 object was null so how null object notify its data
Try calling lv.invalidate() after the remove() and see whether that makes any difference.
You should check in your adapter class if it is null then you should not fetch value from it......that's the main reason why you are getting exception as you are fetching the value from null variable.Put check there.
For setVisibility to Work:
You create your main.xml
Add to it a ListView
<?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/sherif.android.deedz"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:layout_width="match_parent"
android:layout_height="match_parent" android:id="#+id/myListView"
android:divider="#ffa500" android:dividerHeight="1px"
android:background="#drawable/somedrawable_xml"
android:choiceMode="singleChoice"></ListView>
</ListView>
Now you can make it GONE
If you want the whole details of this :
Check my answer