ListPopupWindow jumps to top on certain devices when scrolled - android

I'm building a search field using a ListPopupWindow.
On certain devices the ListPopupWindow changes it's position when scrolled. (It jumps to the top):
Before scrolling:
After scrolling:
I tested this on a Nexus 6P.
On other devices it works normally, it does not change it's initial position when scrolled. This was captured on a Samsung Galaxy A5.
Here's the code:
The Activiyt:
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
EditText itemName;
ListPopupWindow listPopupWindow;
String[] items = {"Item1", "Item2", "Item3", "Item4",
"Item5", "Item6", "Item7", "Item8", "Item9", "Item10"};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
itemName = (EditText) findViewById(
R.id.item_name);
listPopupWindow = new ListPopupWindow(
MainActivity.this);
listPopupWindow.setAdapter(new ArrayAdapter<>(
MainActivity.this,
R.layout.list_item, items));
listPopupWindow.setAnchorView(itemName);
listPopupWindow.setWidth(ListPopupWindow.MATCH_PARENT);
listPopupWindow.setHeight(ListPopupWindow.WRAP_CONTENT);
listPopupWindow.setModal(true);
listPopupWindow.setOnItemClickListener(MainActivity.this);
itemName.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
listPopupWindow.show();
}
});
}
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
itemName.setText(items[position]);
listPopupWindow.dismiss();
}
}
The layout file of the activity:
<?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="match_parent"
android:orientation="vertical">
<EditText
android:id="#+id/item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter item name"
android:textSize="26sp"/>
</LinearLayout>
And the list item layout:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="6dp"
android:textSize="50sp"
android:textStyle="bold"/>
Any ideas how to solve this?

Instead of doing this:
listPopupWindow.setHeight(ListPopupWindow.WRAP_CONTENT);
you have to set the height of your listPopupWindow explicitly. In order to do this, you need to calculate the available height and find the right moment for setting that value.
Get rid of the above line.
Add this to your xml LinearLayout:
android:id="#+id/root"
Add this to your MainActivity:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int popupHeight = findViewById(R.id.root).getHeight() - itemName.getHeight();
listPopupWindow.setHeight(popupHeight);
}
}
Inside a fragment, you don't need onWindowFocusChanged. You can simply post a Runnable to the view:
Activity activity;
EditText itemName;
ListPopupWindow listPopupWindow;
LinearLayout linearLayout;
String[] items = {"Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9", "Item10"};
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof Activity) {
activity = (Activity) context;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
final View view = inflater.inflate(R.layout.fragment_main, container, false);
linearLayout = view.findViewById(R.id.root);
itemName = view.findViewById(R.id.item_name);
listPopupWindow = new ListPopupWindow(activity);
listPopupWindow.setAdapter(new ArrayAdapter<>(activity, R.layout.list_item, items));
listPopupWindow.setAnchorView(itemName);
listPopupWindow.setWidth(ListPopupWindow.MATCH_PARENT);
listPopupWindow.setModal(true);
listPopupWindow.setOnItemClickListener(this);
itemName.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
listPopupWindow.show();
}
});
view.post(new Runnable() {
#Override
public void run() {
int popupHeight = linearLayout.getHeight() - itemName.getHeight();
listPopupWindow.setHeight(popupHeight);
}
});
return view;
}

This worked for me
val popup = ListPopupWindow(context)
try {
val setListItemExpandMax: Method = popup.javaClass.getDeclaredMethod("setListItemExpandMax", Integer.TYPE)
setListItemExpandMax.isAccessible = true
setListItemExpandMax.invoke(popup, 5)
} catch (e: Exception) {
when (e) {
is NoSuchMethodException, is InvocationTargetException, is IllegalAccessException -> {
e.printStackTrace()
}
else -> throw e
}
}

Related

My onitemclick doesn't work after adding button to my ListView in android?

I am facing an issue in my application is that when i add a Button bottom of my ListView in android it's onItemClick doesn't work i am unable to click any item of ListView.
For reference i am providing codes below : -
Custom Adapter Class :
Context context;
String [] Heading= {"Triceps"};
String [] Subheading= {"Triceps the essintial part of an exercise it will increase you muscle power..."};
int [] gif = {R.drawable.triceps };
public custom_adapter(Context ctx) {
this.context=ctx;
}
#Override
public int getCount() {
return Heading.length;
}
#Override
public Object getItem(int position) {
return Heading[position];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
if(view==null){
LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view=inflater.inflate(R.layout.customlayout,null);
}
ImageView imageView=(ImageView) view.findViewById(R.id.imgId);
TextView view1=(TextView) view.findViewById(R.id.Heading);
TextView view2=(TextView) view.findViewById(R.id.Subheading);
imageView.setImageResource(gif[position]);
view1.setText(Heading[position]);
view2.setText(Subheading[position]);
return view;
}}
Main Java class :
ListView listView;
Button btn_start;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.list);
custom_adapter adapter = new custom_adapter(this);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(getApplicationContext(), workout_detail.class);
intent.putExtra("Position", position);
startActivity(intent);
}
});
btn_start = (Button) findViewById(R.id.btn_start);
btn_start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}}
Xml file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
android:background="#abf5f5">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="650dp"
android:background="#abf5f5"/>
<Button
android:id="#+id/btn_start"
android:layout_marginTop="8dp"
android:layout_width="match_parent"
android:layout_below="#+id/list"
android:layout_height="65dp"
android:text="Start Workout"
android:background="#40f716"/>
</RelativeLayout>
Help me out of this.
Thanks in Advance.
Okay! I have found the answer actually the user have to delete any button in custom layout if any and use the linear layout or constraint layout

onitemclicklistener on listview is not working

I have two button inside mylist.xml which is inserted over listview in main.xml using arrayadapter.It is showing me the data in application but only click functionality is not working.
Not be able to click list and both buttons.
activity_main.xml
( In this file I have just made listview using xml in which my custom list "mylist.xml" is going to inserted. )
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="#+id/lv"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
mylist.xml
( In this file all the content of listview lv which is there on mainactivity.These file need to be inserted in that listview. )
<?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="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginTop="10dp"
android:id="#+id/s"
android:gravity="center_horizontal"
android:textSize="20dp"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="25dp"
android:id="#+id/c"
android:textSize="15dp"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="55dp"
android:id="#+id/d"
android:textSize="15dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="left">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/b1"
android:text="UPDATE"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/b2"
android:text="DELETE"/>
</LinearLayout>
</LinearLayout>
MainActivity Class
public class MainActivity extends AppCompatActivity
{
String S1[]={"hello","1","2"},C1[]={"ello2","1","2"},D1[]={"hello3","3","4"};
Button b1,b2;
ListView lv;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv=findViewById(R.id.lv);
b1=findViewById(R.id.b1);
b2=findViewById(R.id.b2);
// display data
CustomAdapter myAdapter=new CustomAdapter(this,S1,C1,D1);
lv.setAdapter(myAdapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(MainActivity.this,"ello"+position,Toast.LENGTH_LONG).show();
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"ello",Toast.LENGTH_LONG).show();
}
});
b2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"ello",Toast.LENGTH_LONG).show();
}
});
}
});
}
}
CustomAdapter class
public class CustomAdapter extends ArrayAdapter<String>
{
private final Activity context;
private final String Subject1[],Chapter1[],Details1[];
public CustomAdapter(Activity context,String Subject1[], String Chapter1[], String Details1[])
{
super(context,R.layout.mylist,Subject1);
this.context=context;
this.Subject1=Subject1;
this.Chapter1=Chapter1;
this.Details1=Details1;
}
public View getView(int position, View view, ViewGroup parent)
{
LayoutInflater inflater=context.getLayoutInflater();
view=inflater.inflate(R.layout.mylist, null);
TextView s =view.findViewById(R.id.s);
TextView c= view.findViewById(R.id.c);
TextView d= view.findViewById(R.id.d);
s.setText(Subject1[position]);
c.setText(Chapter1[position]);
d.setText(Details1[position]);
return view;
};
}
update the parent layout in your mylist.xml with
android:descendantFocusability="blocksDescendants"
like the following...
<?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="match_parent"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical">
If any row item of list contains focusable or clickable view then
OnItemClickListener won't work.
I have found the solution here
Alternatively, you may try setting onClickListeners under getView() method of the list adapter like this (make int position parameter of getView() method final and use it inside your onclick() method). Just copy and paste the getView() method in your adapter ...
public View getView(final int position, View view, ViewGroup parent)
{
LayoutInflater inflater=context.getLayoutInflater();
view=inflater.inflate(R.layout.mylist, null);
TextView s =view.findViewById(R.id.s);
TextView c= view.findViewById(R.id.c);
TextView d= view.findViewById(R.id.d);
s.setText(Subject1[position]);
c.setText(Chapter1[position]);
d.setText(Details1[position]);
//Do like this
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Do whatever you want here with the position
}
});
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context,"BUTTON1 clicked: position=" + position,Toast.LENGTH_LONG).show();
}
});
b2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context,"BUTTON2 clicked: position=" + position,Toast.LENGTH_LONG).show();
}
});
return view;
};
Try this :
In MainActivity :
public class MainActivity extends AppCompatActivity{
String S1[]={"hello","1","2"},C1[]={"ello2","1","2"},D1[]={"hello3","3","4"};
ListView lv;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv=findViewById(R.id.lv);
// display data
CustomAdapter myAdapter=new CustomAdapter(this,S1,C1,D1);
lv.setAdapter(myAdapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// this click work for only on list items not work on list components
// you have to do this functionality in your **CustomAdapter** for list components.
}
});
}
}
Now, in CustomAdapter :
public class CustomAdapter extends ArrayAdapter<String>{
private final Activity context;
private final String Subject1[],Chapter1[],Details1[];
public CustomAdapter(Activity context,String Subject1[], String Chapter1[], String Details1[])
{
super(context,R.layout.mylist,Subject1);
this.context=context;
this.Subject1=Subject1;
this.Chapter1=Chapter1;
this.Details1=Details1;
}
public View getView(int position, View view, ViewGroup parent)
{
LayoutInflater inflater=context.getLayoutInflater();
view=inflater.inflate(R.layout.mylist, null);
TextView s =view.findViewById(R.id.s);
TextView c= view.findViewById(R.id.c);
TextView d= view.findViewById(R.id.d);
Button b1 = view.findViewById(R.id.b1);
Button b2 = view.findViewById(R.id.b2);
s.setText(Subject1[position]);
c.setText(Chapter1[position]);
d.setText(Details1[position]);
// here you have to do click thing :
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"HELLO BUTTON 1",Toast.LENGTH_LONG).show();
}
});
b2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"HELLO BUTTON 2",Toast.LENGTH_LONG).show();
}
});
return view;
};
}
There are two places where you can put the butonClick.
1: Inside your adapter:-
public class CustomAdapter extends ArrayAdapter<String>{
private final Activity context;
private final String Subject1[],Chapter1[],Details1[];
public CustomAdapter(Activity context,String Subject1[], String Chapter1[], String Details1[])
{
super(context,R.layout.mylist,Subject1);
this.context=context;
this.Subject1=Subject1;
this.Chapter1=Chapter1;
this.Details1=Details1;
}
public View getView(int position, View view, ViewGroup parent)
{
LayoutInflater inflater=context.getLayoutInflater();
view=inflater.inflate(R.layout.mylist, null);
TextView s =view.findViewById(R.id.s);
TextView c= view.findViewById(R.id.c);
TextView d= view.findViewById(R.id.d);
Button b1 = view.findViewById(R.id.b1);
Button b2 = view.findViewById(R.id.b2);
s.setText(Subject1[position]);
c.setText(Chapter1[position]);
d.setText(Details1[position]);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Button1 click here
Toast.makeText(getApplicationContext(),"BUTTON 1 Position : "+ position,Toast.LENGTH_LONG).show();
}
});
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Button2 click here
Toast.makeText(getApplicationContext(),"BUTTON 2 Position : "+ position,Toast.LENGTH_LONG).show();
}
});
return view;
};
}
2:In your Activity:-
to put a buttonClick listener inside your listview first make a listener like:
public interface OnclickListener {
void onButtonClickHere(int position);
}
And then in your Activity:
ListAdapter adapter;
OnclickListener onclickListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
onclickListener = this;
filterNames = getResources().getStringArray(R.array.finalfilter_names);
filterMethods = getResources().getStringArray(R.array.filter_method_names);
listView = (ListView)
findViewById(R.id.idListView);
adapter = new ListAdapter(groceryList, getApplicationContext(), onclickListener);
}
you can access the onclick here
#Override
public void onButtonClickHere(int position) {
Filter filter = null;
if(position == 0){
filter = FilterPack.getAweStruckVibeFilter(this);
}else if(position == 1){
filter = FilterPack.getMarsFilter(this);
}else if(position == 2){
filter = FilterPack.getStarLitFilter(this);
}
filtered = bitmap.copy(bitmap.getConfig(), true);
// apply filter
imgImage.setImageBitmap(filter.processFilter(filtered));
// struck mars starlit
}
And then in your adapter :
add this in your constructor
OnclickListener onclickListener;
public ListAdapter(List<ButtonsBean> horizontalGrocderyList, Context context,OnclickListener onclickListener ){
this.buttonsBeanList = horizontalGrocderyList;
this.context = context;
this.onclickListener = onclickListener; // Add this to your constructor
}
and inside getView()
add this line:
onclickListener.onButtonClickHere(position);

ListView with text and checkbox

I used RelativeLayout for my ListView.
<?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="wrap_content"
android:orientation="vertical"
android:padding="6dip" >
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="CheckBox" />
<TextView
android:id="#+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/checkBox1"
android:layout_alignBottom="#+id/checkBox1"
android:layout_toRightOf="#+id/checkBox1"
android:text="TextView" />
</RelativeLayout>
Here is my ListView code,
private void displayList(){
ArrayList<String> diyListArray = new ArrayList<String>();
diyListArray.add("1");
diyListArray.add("2");
diyListArray.add("3");
diyListArray.add("4");
diyListArray.add("5");
diyListArray.add("6");
diyListArray.add("7");
listAdapter = new ArrayAdapter<String>(this, R.layout.selectrow, R.id.test, diyListArray);
diyList.setAdapter( listAdapter );
}
We can see here that I used ArrayAdapter with resource id of TextView.
I am able to display the checkboxes and their corresponding texts.
How can I get user selected texts from checkboxes?
Try the following:
Demo10.class:----
public class Demo10 extends AppCompatActivity implements Listener {
private ListView lv;
private boolean[] state_ = new boolean[4];
private String[] text_ = new String[4];
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo11);
for(int i = 0 ; i<4 ; i++) {
state_[i] = false;
text_[i] = "text"+i;
}
lv = (ListView) findViewById(R.id.lv);
lv.setAdapter(new ItemAdapter(Demo10.this , this));// This includes a Listener that listens to onCheckBoxStateChanges.
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { // used to handle ListView onItemClicks and how they should affect the corresponding checkBox
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CheckBox cb = view.findViewById(R.id.cb);
cb.setChecked(!cb.isChecked());
displayCheckBoxStateText();
}
});
}
private void displayCheckBoxStateText(){
for(int i = 0 ; i<4 ; i++){
Log.e("CheckBox", text_[i]+" : " + state_[i]);
}
}
#Override
public void checkBox1(boolean state) {
state_[0] = state;
displayCheckBoxStateText();
}
#Override
public void checkBox2(boolean state) {
state_[1] = state;
displayCheckBoxStateText();
}
#Override
public void checkBox3(boolean state) {
state_[2] = state;
displayCheckBoxStateText();
}
#Override
public void checkBox4(boolean state) {
state_[3] = state;
displayCheckBoxStateText();
}
}
ItemAdapter.class:-----
public class ItemAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater layoutInflater;
private Listener callback;
public ItemAdapter(Context c , Listener l) {
mContext = c;
callback = l;
layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return s.length;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
CheckBox cb;
View view = convertView;
if (convertView == null) {
if (layoutInflater != null) {
view = layoutInflater.inflate(R.layout.demo10, null);
}
}
cb = view.findViewById(R.id.cb);
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
switch (position) {
case 0:
callback.checkBox1(isChecked);
break;
case 1:
callback.checkBox2(isChecked);
break;
case 2:
callback.checkBox3(isChecked);
break;
case 3:
callback.checkBox4(isChecked);
break;
default:
break;
}
}
});
cb.setText(s[position]);
return view;
}
private String[] s = {
"test1",
"test2",
"test3",
"test4"
};
}
Listener interface:----
public interface Listener {
public void checkBox1(boolean state);
public void checkBox2(boolean state);
public void checkBox3(boolean state);
public void checkBox4(boolean state);
}
demo10.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="wrap_content"
android:orientation="vertical"
android:padding="6dip" >
<CheckBox
android:id="#+id/cb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="" />
</RelativeLayout>
demo11.xml:-----
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/lv">
</ListView>
</android.support.constraint.ConstraintLayout>
Make choice mode first
listview.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
I am making a button by clicking on it you can retrieve all the items you checked
button.setOnClickListener(this);
#Override
public void onClick(View v) {
SparseBooleanArray checked = listview.getCheckedItemPositions();
ArrayList<String> selectedItems = new ArrayList<String>();
for (int i = 0; i < checked.size(); i++) {
int position = checked.keyAt(i);
if (checked.valueAt(i))
selectedItems.add(listAdapter.getItem(position));
}
}
here you get all the items checked in your selectedItems ArrayList.
You can override getView() of ArrayAdapter and handles views by yourself. Replace:
listAdapter = new ArrayAdapter<String>(this, R.layout.selectrow, R.id.test, diyListArray);
with
listAdapter = new ArrayAdapter<String>(this, R.layout.selectrow, diyListArray){
boolean[] checked = new boolean[diyListArray.size()];
#NonNull
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
if(convertView == null) convertView = getLayoutInflater().inflate(R.layout.selectrow, null);
TextView textView = convertView.findViewById(R.id.test);
CheckBox checkBox = convertView.findViewById(R.id.checkBox1);
textView.setText(getItem(position));
checkBox.setChecked(checked[position]);
checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
checked[position] = !checked[position];
String msg = "Checked Item: ";
if(!checked[position]) msg = "Unchecked Item: ";
Toast.makeText(getContext(), msg + getItem(position), Toast.LENGTH_SHORT).show();
notifyDataSetChanged();
}
});
return convertView;
}
};
I have blog about ListView: http://programandroidlistview.blogspot.com/
Hope that helps!

How to implement search with Spinner in Android?

My code for Spinner is below:
String[] countryNames = {"Select Country", "India", "China", "Australia", "Portugle", "America", "New Zealand"};
Spinner spinner = (Spinner) findViewById(R.id.simpleSpinner);
hintAdapter = new CustomArrayAdapter(getApplicationContext(), R.layout.simple_row,countriesList,getApplicationContext());
spinner.setAdapter(hintAdapter);
I want to implement search in Spinner.
How can I achieve that?
Use SearchableSpinner Lib, there is list of SearchableSpinner Library available just pick one of those which is better https://github.com/search?utf8=%E2%9C%93&q=searchable+spinner
Go for AutocompleteTextview
this example will help you
I found the following solution here:
/**
* A modified Spinner that doesn't automatically select the first entry in the list.
*
* Shows the prompt if nothing is selected.
*
* Limitations: does not display prompt if the entry list is empty.
*/
public class NoDefaultSpinner extends Spinner {
public NoDefaultSpinner(Context context) {
super(context);
}
public NoDefaultSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setAdapter(SpinnerAdapter orig ) {
final SpinnerAdapter adapter = newProxy(orig);
super.setAdapter(adapter);
try {
final Method m = AdapterView.class.getDeclaredMethod(
"setNextSelectedPositionInt",int.class);
m.setAccessible(true);
m.invoke(this,-1);
final Method n = AdapterView.class.getDeclaredMethod(
"setSelectedPositionInt",int.class);
n.setAccessible(true);
n.invoke(this,-1);
}
catch( Exception e ) {
throw new RuntimeException(e);
}
}
protected SpinnerAdapter newProxy(SpinnerAdapter obj) {
return (SpinnerAdapter) java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
new Class[]{SpinnerAdapter.class},
new SpinnerAdapterProxy(obj));
}
/**
* Intercepts getView() to display the prompt if position < 0
*/
protected class SpinnerAdapterProxy implements InvocationHandler {
protected SpinnerAdapter obj;
protected Method getView;
protected SpinnerAdapterProxy(SpinnerAdapter obj) {
this.obj = obj;
try {
this.getView = SpinnerAdapter.class.getMethod(
"getView",int.class,View.class,ViewGroup.class);
}
catch( Exception e ) {
throw new RuntimeException(e);
}
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
try {
return m.equals(getView) &&
(Integer)(args[0])<0 ?
getView((Integer)args[0],(View)args[1],(ViewGroup)args[2]) :
m.invoke(obj, args);
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
protected View getView(int position, View convertView, ViewGroup parent)
throws IllegalAccessException {
if( position<0 ) {
final TextView v =
(TextView) ((LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE)).inflate(
android.R.layout.simple_spinner_item,parent,false);
v.setText(getPrompt());
return v;
}
return obj.getView(position,convertView,parent);
}
}
}
After trying a lot of libraries and method, I finally created my custom searchable spinner. The code I am attaching is at a very preliminary level which I will be updating as I do in my project. I am also writing the complete method of how to use it.
All Layouts
searchable_spinner.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="#+id/spinner_search_bar"
android:layout_width="match_parent"
android:layout_height="35dp"
android:hint="Select A Company"
android:cursorVisible="false"
android:background="#drawable/white_rect_fillet_border"
android:paddingHorizontal="10dp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/ledger_list"
android:layout_width="match_parent"
android:layout_height="300dp"
android:visibility="gone"
android:layout_marginHorizontal="10dp"/>
</LinearLayout>
</FrameLayout>
actity_or_frag_layout.xml remember to include this as last and align according to your parent layout.
<FrameLayout
android:id="#+id/spinner_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:background="#drawable/white_rect_fillet_border"
app:layout_constraintTop_toTopOf="parent">
<include layout="#layout/searchable_spinner" />
</FrameLayout>
list_adapter_element.xml
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TableRow>
<TextView
android:id="#+id/txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical=5dp"
android:gravity="center_vertical"/>
</TableRow>
</TableLayout>
All Drawables
white_rect_fillet_border.xml
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#android:color/white"/>
<corners android:radius="5dp" />
<stroke android:color="#android:color/darker_gray"
android:width="1dp" />
</shape>
CustomListAdapter.java
public class CustomListAdapter extends
RecyclerView.Adapter<CustomListAdapter.ViewHolder> {
private final Activity context;
private Fragment fragment;
private ArrayList<LedgerListObject> ledgerlist; //replace LedgerListObject with your object or simply String everywhere in this code.
public CustomListAdapter(Activity context, Fragment fragment,
ArrayList<LedgerListObject> ledgerlist) {
this.context = context;
this.fragment = fragment;
this.ledgerlist = ledgerlist;
}
public void updateList(ArrayList<LedgerListObject> newList){
ledgerlist = newList;
notifyDataSetChanged();
}
#NonNull
#Override
public CustomListAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.list_adapter_element, null, true);
return new ViewHolder(rowView);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
holder.txtTitle.setText(ledgerlist.get(position).LedgerName);
holder.txtTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyFragment.LedgerID = ledgerlist.get(position).LedgerID; //MyFragment can be replaced with the name of your activity or fragment
MyFragment.ledgerListView.setVisibility(View.GONE);
MyFragment.spinnerSearch.setText(ledgerlist.get(position).LedgerName);
MyFragment.spinnerSearch.setCursorVisible(false);
}
});
}
#Override
public int getItemCount() {
return ledgerlist.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView txtTitle;
ViewHolder(#NonNull View itemView) {
super(itemView);
txtTitle = (TextView) itemView.findViewById(R.id.txt);
}
}
}
MyFragment.java
public class MyFragment extends Fragment{
ArrayList<LedgerListObject> ledgerlist = new ArrayList<LedgerListObject>();
public static int LedgerID = 0;
CustomListAdapter ledgerAdapter;
FrameLayout spinnerFrame;
public static EditText spinnerSearch;
public static RecyclerView ledgerListView;
#SuppressLint("ClickableViewAccessibility")
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState){
View root = inflater.inflate(R.layout.fragment_ledger, container, false);
super.onCreate(savedInstanceState);
spinnerFrame = root.findViewById(R.id.spinner_frame);
spinnerSearch = root.findViewById(R.id.spinner_search_bar);
ledgerListView = root.findViewById(R.id.ledger_list);
spinnerSearch.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ledgerListView.setVisibility(View.VISIBLE);
spinnerSearch.setCursorVisible(true);
return false;
}
});
spinnerSearch.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
try{
filter(s.toString());
}catch (Exception e){e.printStackTrace();}
}
});
GridLayoutManager listgridLayoutManager = new GridLayoutManager(getContext(), 1,
RecyclerView.VERTICAL, false);
ledgerListView.setLayoutManager(listgridLayoutManager);
//todo: your method of adding objects to your ledgerlist
ledgerAdapter = new CustomListAdapter(getActivity(), LedgerFragment.this, ledgerlist);
ledgerListView.setAdapter(ledgerAdapter);
return root;
}
}
Try it and if there is any issue in this, please feel free to ask and I will resolve it
You Can show Searchable Spinner in Dialog. here is all steps
Step 1: make a TextView inside activity_main.xml.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="#+id/text_view_for_dropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:hint="Select Number"
android:background="#android:drawable/editbox_background"
app:drawableEndCompat="#drawable/ic_dropdown" />
<!-- "#drawable/ic_dropdown" is "vector asset" of down arrow sign -->
</LinearLayout>
Step 2: make new layout (res>layout>layout_searchable_spinner.xml) that we will show inside Dialog.
layout_searchable_spinner.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="match_parent"
android:orientation="vertical"
android:layout_margin="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:fontFamily="monospace"
android:text="Select Number"
/>
<EditText
android:id="#+id/editText_of_searchableSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Search..."
android:padding="12dp"
android:singleLine="true"
android:background="#android:drawable/editbox_background"
/>
<ListView
android:id="#+id/listView_of_searchableSpinner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
/>
</LinearLayout>
Step 3: write all code in MainActivity.Java
MainActivity.Java
public class MainActivity extends AppCompatActivity {
ArrayList<String> arrayList;
TextView textViewSpinner;
Dialog dialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//provide size to arrayList
arrayList=new ArrayList<>();
//call this spinner function
funCustomSpinner();
}
public void funCustomSpinner(){
//we are adding values in arraylist
arrayList.add("Item 1");
arrayList.add("Item 2");
arrayList.add("Item 3");
arrayList.add("Item 4");
arrayList.add("Item 4");
arrayList.add("Item 4");
//provide id to textview and set onClick lister
textViewSpinner=findViewById(R.id.text_view_for_dropdown);
textViewSpinner.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog=new Dialog(MainActivity.this);
//set (our custom layout for dialog)
dialog.setContentView(R.layout.layout_searchable_spinner);
//set transparent background
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
//show dialog
dialog.show();
//initialize and assign variable
EditText editText=dialog.findViewById(R.id.editText_of_searchableSpinner);
ListView listView=dialog.findViewById(R.id.listView_of_searchableSpinner);
//array adapter
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<>(MainActivity.this,
androidx.appcompat.R.layout.support_simple_spinner_dropdown_item,arrayList);
listView.setAdapter(arrayAdapter);
//Textwatcher for change data after every text type by user
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
//filter arraylist
arrayAdapter.getFilter().filter(charSequence);
}
#Override
public void afterTextChanged(Editable editable) {
}
});
// listview onitem click listener
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
textViewSpinner.setText(arrayAdapter.getItem(i));
Toast.makeText(MainActivity.this, "Selected:"+ arrayAdapter.getItem(i), Toast.LENGTH_SHORT).show();
//dismiss dialog after choose
dialog.dismiss();
}
});
}
});
}
Happy Coding:)

setOnItemClickListener doesn't work for a button in a ListView

I am trying to place a button in each list item. This is the idea:
Text1____________[btn]
Text2____________[btn]
etc...
The XML for the items is:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:id="#+id/list_item_textview"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/deleteButton"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:background="#null"
android:clickable="true"
android:focusable="false"
android:src="#drawable/ic_delete_black_24dp"/>
</RelativeLayout>
There are two activities sharing the same fragment. This fragment uses a SimpleCursorAdapter to fetch the data from a database. That is working perfectly.
After creating and setting the adapter, I try to find the button and do a setOnClickListener. This is NOT working.
Here is the code for the onCreateView method in the fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_scroll, container, false);
ListView listView = (ListView) rootView.findViewById(R.id.listview_item);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
getActivity(),
R.layout.list_item,
((ListItems)getActivity()).getCursor(1,1),
new String[] {((ListItems) getActivity()).getColumnName()},
new int[] {R.id.list_item_textview}, 0);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(getActivity(), ((ListItems) getActivity()).getGoToClass());
intent.putExtra("apiary_id",(int) id);
intent.putExtra("hive_id", -1);
startActivity(intent);
}
});
/* SOMEWHERE BELOW IS THE PROBLEM */
View list_item_view = inflater.inflate(R.layout.list_item, container, false);
ImageButton deleteButton = (ImageButton) list_item_view.findViewById(R.id.deleteButton);
System.out.println("====================>" + deleteButton.toString()); //This prints something which includes the id of the button, so it is finding it.
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("THIS IS NOT WORKING!!!!");
}
});
return rootView;
}
This is my first android application and I'm having this problem for a few days now without any progress. Any hint is greatly appreciated!
Thank you very much!
Make a custom list adapter like this
public class CustomListAdapter extends BaseAdapter {
private String[] items;
private LayoutInflater inflater;
Context context;
public CustomListAdapter(Context c, String[] items) {
this.items = items;
inflater =LayoutInflater.from(c);
context = c;
}
#Override
public int getCount() {
return items.length;
}
#Override
public Object getItem(int location) {
return items[location];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = inflater.inflate(R.layout.list_item, null);
TextView txt = (TextView) convertView.findViewById(R.id.list_item_textview);
ImageButton button = (ImageButton) convertView.findViewById(R.id.deleteButton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "clicked ",
Toast.LENGTH_SHORT).show();
}
});
txt.setText(""+items[position]);
return convertView;
}
}
and in your fragment
CustomListAdapter customListAdapter;
customListAdapter = new CustomListAdapter(getActivity(),str);
list.setAdapter(customListAdapter);
hope this will help you !!!

Categories

Resources