I have to show two section in AutoCompleteTextView (Something like this):
I have created a custom layout which have two CardViews and each CardView have three TextViews. Right now I am not distributing the section on the basis of type. The whole data is loaded into one section.
Activity
final AutocompleteLocalityAdapter adapterLocalities = new AutocompleteLocalityAdapter(context,
R.layout.support_simple_spinner_dropdown_item, new ArrayList<Locality>());
AutocompleteLocalityAdapter
public class AutocompleteLocalityAdapter extends ArrayAdapter<Locality> {
public AutocompleteLocalityAdapter(Context context, int layout, List<Locality> localities) {
super(context, layout, localities);
this.localities = localities;
updateList("");
}
In updateList method I am making a new network call to fill the data in Locality class.
What do I need to do to categories the search result as per given image? ArrayAdapter is not going to work here for sure.
The possible solution I am thinking here is:
Replace ArrayAdapter to RecyclerViewAdapter.
Any hint will be appreciable.
The possible makeshift to this solution is PopUpWindow. Inside the PopUpWindow I put two RecyclerView and populate them through network calls.
dashboard_profile_popup_window
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="#dimen/margin_low"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="#+id/locationCardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="#dimen/corner_radius"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/landmark"
android:textStyle="bold" />
<ListView
android:id="#+id/localityView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="#+id/landmarkCardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="#dimen/corner_radius"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/location"
android:textStyle="bold" />
<ListView
android:id="#+id/landmarkView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v7.widget.CardView>
CustomWidget
public class CustomAutoCompleteView extends EditText {
private Context context;
TextListViewAdapter locationAdapter;
TextListViewAdapter landmarkAdaper;
PopupWindow pwindow;
ClickListener clickListener;
public CustomAutoCompleteView(Context context) {
super(context);
this.context = context;
setCustomization();
}
public void closeWindow(){
pwindow.dismiss();
}
public CustomAutoCompleteView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
setCustomization();
}
public CustomAutoCompleteView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
setCustomization();
}
public void updateList(List<LocalityEntity> locationList, List<LocalityEntity> landmarkList) {
if (pwindow == null) {
initPopupWindow();
}
locationAdapter.updateList(locationList);
landmarkAdaper.updateList(landmarkList);
}
public void initPopupWindow() {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = layoutInflater.inflate(R.layout.dashboard_profile_popup_window, null);
ListView landmarkRecyclerView = (ListView) layout.findViewById(R.id.localityView);
ListView localityRecyclerView = (ListView) layout.findViewById(R.id.landmarkView);
landmarkRecyclerView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String text = ((TextView) view.findViewById(R.id.localityText)).getText().toString();
String gid = ((TextView) view.findViewById(R.id.localityGID)).getText().toString();
clickListener.placeSelected(gid);
}
});
localityRecyclerView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String text = ((TextView) view.findViewById(R.id.localityText)).getText().toString();
String gid = ((TextView) view.findViewById(R.id.localityGID)).getText().toString();
clickListener.placeSelected(gid);
}
});
landmarkRecyclerView.setAdapter(landmarkAdaper);
localityRecyclerView.setAdapter(locationAdapter);
pwindow = new PopupWindow(context);
pwindow.setContentView(layout);
pwindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
pwindow.setWidth(this.getWidth());
pwindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
pwindow.setFocusable(true);
pwindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
#Override
public void onDismiss() {
pwindow = null;
}
});
pwindow.showAsDropDown(this);
}
private void setCustomization() {
locationAdapter = new TextListViewAdapter(getContext());
landmarkAdaper = new TextListViewAdapter(getContext());
initPopupWindow();
}
public void setClickListener(ClickListener clickListener) {
this.clickListener = clickListener;
}
public interface ClickListener {
void placeSelected(String gid);
}
}
Now call this customViewWidget through following code:
place_pop_up.setClickListener(this);
place_pop_up.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) {
}
private Timer timer = new Timer();
private final long DELAY = 2000;
#Override
public void afterTextChanged(final Editable s) {
if (s.length() > 3) {
timer.cancel();
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
getAutoCompleteSearchResult(s.toString());
}
}, DELAY);
}
}
});
In getAutoCompleteSearchResult make the network call and call place_pop_up.updateList(locality, landmark);
Related
I tried all the solution that i found here in the stackoverflow but it seems like none of them work.
Here is my main activity:
public class MerchantLocatorActivity extends AppCompatActivity implements OnMapReadyCallback {
public void init(){
merchantLocatorResponseObject = new MerchantLocatorResponse();
merchantLocatorResponseObject.setTitle("Spherical");
merchantLocatorResponseObject.setAddress("8007 Pioneer St, Kapitolyo, Mandaluyong, 1550 Metro Manila");
merchantLocatorResponseObject.setLatitude( 14.573249);
merchantLocatorResponseObject.setLongitude(121.057022);
merchantLocatorObjectArray.add(merchantLocatorResponseObject);
merchantLocatorResponseObject = new MerchantLocatorResponse();
merchantLocatorResponseObject.setTitle("Globe");
merchantLocatorResponseObject.setAddress("SCT, 584 Shaw Blvd, Mandaluyong, 1552 Metro Manila");
merchantLocatorResponseObject.setLatitude(14.585095);
merchantLocatorResponseObject.setLongitude(121.048893);
merchantLocatorObjectArray.add(merchantLocatorResponseObject);
merchantLocatorResponseObject = new MerchantLocatorResponse();
merchantLocatorResponseObject.setTitle("Sparndium");
merchantLocatorResponseObject.setAddress("Xavier, San Juan, 1502 Metro Manila");
merchantLocatorResponseObject.setLatitude(14.601918);
merchantLocatorResponseObject.setLongitude(121.042169);
merchantLocatorObjectArray.add(merchantLocatorResponseObject);
addMarker();
}
#OnClick(R.id.fab)
public void showAccToDialog() {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
View alertView = LayoutInflater.from(this).inflate(R.layout.dialog_biller, null);
alertDialogBuilder.setView(alertView);
final AlertDialog dialog = alertDialogBuilder.create();
dialog.show();
final ListView listViewBillers = (ListView) dialog.findViewById(R.id.biller_institutions_listview);
if (listViewBillers != null) {
MerchantLocatorAdapter adapter = new MerchantLocatorAdapter(
this, R.layout.merchant_locator_adapter, merchantLocatorObjectArray);
listViewBillers.setAdapter(adapter);
listViewBillers.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
geoLocate(merchantLocatorObjectArray,position);
DebugUtils.log("TESTTESTACTIVITYZXC");
DebugUtils.showToast(MerchantLocatorActivity.this,"HAHAHAH");
dialog.dismiss();
}
});
final EditText mSearchedittext = (EditText) dialog.findViewById(R.id.search_edittext);
mSearchedittext.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) {
final ArrayList<MerchantLocatorResponse> searchResultObject = new ArrayList<>();
searchResultObject.clear();
for (int hay = 0; hay <= merchantLocatorObjectArray.size() - 1; hay++) {
if ( merchantLocatorObjectArray.get(hay).getTitle().toLowerCase().contains(charSequence)) {
searchResultObject.add( merchantLocatorObjectArray.get(hay));
}
}
MerchantLocatorAdapter adapter = new MerchantLocatorAdapter(
MerchantLocatorActivity.this, R.layout.merchant_locator_adapter, searchResultObject);
listViewBillers.setAdapter(adapter);
listViewBillers.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long arg) {
geoLocate(searchResultObject,position);
dialog.dismiss();
}
});
}
#Override
public void afterTextChanged(Editable editable) {
}
});
}
}
}
i remove some part of the code because i think it's un necessary to include but let me know if there's some part that i need some clarification.
currently in my main activity, i'm calling a dialog that contains a listview and in my listview i have items.
My problem is i can't select any of my items even thought i have my setOnitemclick listener.
here is my adapter:
public class MerchantLocatorAdapter extends BaseAdapter {
private int resourceLayout;
private Context mContext;
ArrayList<MerchantLocatorResponse> merchantLocatorarray = new ArrayList<>();
public MerchantLocatorAdapter(Context context, int resource, ArrayList<MerchantLocatorResponse> merchantLocatorResponsesobjectArray) {
this.resourceLayout = resource;
this.mContext = context;
this.merchantLocatorarray = merchantLocatorResponsesobjectArray;
}
#Override
public int getCount() {
return merchantLocatorarray.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(mContext.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(resourceLayout, parent, false);
}
TextView tt1 = (TextView) convertView.findViewById(R.id.field_name_textview);
TextView tt2 = (TextView) convertView.findViewById(R.id.field_value_textview);
ImageButton direction = (ImageButton) convertView.findViewById(R.id.direction);
tt1.setText(merchantLocatorarray.get(position).getTitle());
tt2.setText(merchantLocatorarray.get(position).getAddress());
return convertView;
}
}
here is my layout for my adapter:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="8dp"
android:elevation="3dp">
<LinearLayout
android:id="#+id/card_overflow"
android:focusable="true"
android:clickable="true"
android:background="#fff"
android:paddingLeft="16dp"
android:paddingRight="0dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="1">
<TextView
android:id="#+id/field_name_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_toLeftOf="#+id/branch_btns"
android:layout_alignParentLeft="true"
android:textSize="17sp"
android:textStyle="bold"
android:textColor="#color/edittext_text"
android:text="test"/>
<LinearLayout
android:id="#+id/branch_btns"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:orientation="horizontal"
>
<ImageButton
android:id="#+id/direction"
android:layout_width="50sp"
android:layout_height="wrap_content"
android:src="#drawable/ic_direction"
android:scaleType="fitCenter"
android:background="#color/translucent_clear_bg"
/>
<ImageButton
android:id="#+id/btn_branch_phone"
android:layout_width="50sp"
android:layout_height="wrap_content"
android:src="#drawable/ic_call_phone"
android:scaleType="fitCenter"
android:background="#color/translucent_clear_bg"
/>
</LinearLayout>
</RelativeLayout>
<View
android:id="#+id/seperator"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginBottom="5dp"
android:background="#android:color/darker_gray"
android:visibility="gone"
android:layout_marginTop="2dp"/>
<TextView
android:id="#+id/field_value_textview"
android:textSize="14sp"
android:textColor="#color/edittext_tint"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
i tried every solution that i found here in stackoverflow, and yet i can't still click my item. so please don't mark this as a duplicate.
if there's any part of the code that need clarification, please leave a comment and i'll answer as soon as possible. thanks.
Try to use Observable in you custom adapter:
// Define
private final PublishSubject<MerchantLocatorResponse> onItemClick = PublishSubject.create();
// Create the observable method
public Observable<ConversationMessage> getObservable(){
return onItemClick;
}
// Set the onClickListener into getView()
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClick.onNext(merchantLocatorarray.get(position));
}
});
Then, in your main activity listen to it and handle the click:
#OnClick(R.id.fab)
public void showAccToDialog() {
// bla bla bla
listViewBillers.setAdapter(adapter);
listViewBillers.getObservable().subscribe(geoLocate);
// bla bla bla
}
Consumer<MerchantLocatorResponse> geoLocate = new Consumer<MerchantLocatorResponse>() {
#Override
public void accept(MerchantLocatorResponse mlr) {
// Code after click event
}
};
Add those library in your gradle:
implementation "io.reactivex.rxjava2:rxjava:2.1.5"
implementation "io.reactivex.rxjava2:rxandroid:2.0.1"
Add convertView.setOnclickListener() in your code. Try below code in your adapter
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(mContext.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(resourceLayout, parent, false);
}
TextView tt1 = (TextView) convertView.findViewById(R.id.field_name_textview);
TextView tt2 = (TextView) convertView.findViewById(R.id.field_value_textview);
ImageButton direction = (ImageButton) convertView.findViewById(R.id.direction);
tt1.setText(merchantLocatorarray.get(position).getTitle());
tt2.setText(merchantLocatorarray.get(position).getAddress());
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, String.valueOf(position), Toast.LENGTH_SHORT).show();
}
});
return convertView;
} }
I have ListView and it include 2 EditTextI want to initialize 6 empty EditText when activity started.How can I do that?
I can not add list null Model and set it so I dont know how can i handle it.
This is listview_row.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="#+id/SerialNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="3"
android:ellipsize="end"
android:padding="5dp"
android:singleLine="true">
<requestFocus />
</EditText>
<EditText
android:id="#+id/countItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:padding="5dp"
android:singleLine="true"
android:inputType="number">
</EditText>
This is my layout;
activity_reader.xml
<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">
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content""
android:text="btn" />
<GridLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="#null" />
</GridLayout>
Here is the ListView Adapter;
public class ListViewAdapter extends BaseAdapter {
public ArrayList<Model> productList;
Activity activity;
ViewHolder holder;
public ListViewAdapter(Activity activity, ArrayList<Census> productList) {
super();
this.activity = activity;
this.productList = productList;
}
#Override
public int getCount() {
return productList.size();
}
#Override
public Object getItem(int position) {
return productList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
EditText SerialNumber;
EditText countItem;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = activity.getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.listview_row, null);
holder = new ViewHolder();
holder.SerialNumber = (EditText) convertView.findViewById(R.id.SerialNumber );
holder.countItem = (EditText) convertView.findViewById(R.id.countItem );;
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.SerialNumber.addTextChangedListener(new TextWatcher() { #Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
holder.SerialNumber.requestFocus();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
holder.censusRowSerialNumber.requestFocus();
}
#Override
public void afterTextChanged(Editable s) {
//holder.countItem.requestFocus();
}
});
Model item = productList.get(position);
holder.SerialNumber.setText(item.getID().toString());
holder.countItem.setText(String.valueOf(item.getQuantity()));
return convertView;
}
}
Here is the Activity;
public class ReaderActivity extends AppCompatActivity {
EditText countItem,SerialNumber;
private ArrayList<Model> csList;
Model item;
ListViewAdapter adapter;
ListView lview;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reader);
csList = new ArrayList<Model>();
lview = (ListView) findViewById(R.id.listview);
adapter = new ListViewAdapter(this, csList);
SerialNumber= findViewById(R.id.SerialNumber);
countItem = findViewById(R.id.countItem );
lview.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
For achieving CRUD operations, its good to go with Custom Layouts.
For instance a LinearLayout, who's default layout is already defined. Now according to runtime requirement/parameters you can add/edit/delete all these. For which the logic can be completely yours. This is handy than creating a static view and manipulating.
Let me show you custom layouts preparation and adding into a rootiew. I have given example where layout landing_hori_view is having an EditText and Button
public class LandingHorizontalView extends LinearLayout implements View.OnClickListener{
public LandingHorizontalView(Context context){
super(context);
initialize();
}
public LandingHorizontalView(Context context, ModelClassObject modelObject,ButtonClicked listener){
super(context);
mTypeContent = modelObject;//If you want to pass some params for population
mListener = listener;
initialize();
}
private void initialize(){
View view = LayoutInflater.from(getContext()).inflate(R.layout.landing_hori_view, this, true);
EditText edtOne =findViewById(R.id.txt_price_list);
Button button= findViewById(R.id.btn_place_order);
button.setTag(count);
button.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v instanceof Button){
int count = (int) v.getTag();
mListener.onButtonClicked(count);
}
}
public interface ButtonClicked{
public void onButtonClicked(int index);
}
}
In your parent activity, implement the interface (here ButtonClicked) and handle click events/manipulating UI etc
#Override
public void onButtonClicked(int index) {
}
Now coming to , how to add these to parent layout, create a ScrollView and include one LinearLayout to which LandinghorizontalView will be added.
Below shows content of my parent Activity
<ScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#android:color/white"
app:layout_constraintTop_toBottomOf="#id/guideline"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/landingScrollLinearView"
>
</LinearLayout>
Now for adding this vew , the following can be done.
LandingHorizontalView horizontalView=new LandingHorizontalView(getActivity(),modelObject,this);
mScrollLinearView.addView(horizontalView);
Now as per your comment, create few LandingHorizontalView and add
to root. Now according to your logic/user interaction , keep on
modifying mScrollLinearView
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:)
I make WearableListView list. Problem is that setting android:layout_height="20dp" doesn't help
How to set height in this case? In Android Wear sample projects Notifications and Timer they also just set atribute android:layout_height="80dp". But I tried to set in the projects android:layout_height="20dp" but it didn't help! (below is my project source code):
list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<base.mobitee.com.mobiteewatch.adapter.HolesListItemLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="20dp"
android:gravity="center_vertical" >
<TextView
android:id="#+id/text_hole"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:textSize="#dimen/list_item_text_size" />
</base.mobitee.com.mobiteewatch.adapter.HolesListItemLayout>
HolesListItemLayout.java:
public class HolesListItemLayout extends LinearLayout
implements WearableListView.OnCenterProximityListener {
private TextView mName;
private final int mFadedTextColor;
private final int mChosenTextColor;
public HolesListItemLayout(Context context) {
this(context, null);
}
public HolesListItemLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public HolesListItemLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
mFadedTextColor = getResources().getColor(R.color.grey);
mChosenTextColor = getResources().getColor(R.color.black);
}
// Get references to the icon and text in the item layout definition
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mName = (TextView) findViewById(R.id.text_hole);
}
#Override
public void onCenterPosition(boolean animate) {
mName.setTextSize(18);
mName.setTextColor(mChosenTextColor);
}
#Override
public void onNonCenterPosition(boolean animate) {
mName.setTextColor(mFadedTextColor);
mName.setTextSize(14);
}
}
HolesListAdapter.java:
public class HolesListAdapter extends WearableListView.Adapter {
private final Context mContext;
private final LayoutInflater mInflater;
public HolesListAdapter(Context context) {
this.mContext = context;
mInflater = LayoutInflater.from(context);
}
#Override
public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new WearableListView.ViewHolder(
mInflater.inflate(R.layout.list_item_hole, null));
}
#Override
public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {
TextView text = (TextView) holder.itemView.findViewById(R.id.text_hole);
text.setText(mContext.getString(R.string.hole_list_item) + " " + (position + 1));
text.setTextColor(mContext.getResources().getColor(android.R.color.black));
holder.itemView.setTag(position);
}
#Override
public int getItemCount() {
return Preferences.HOLES;
}
}
The WearableListView is hard-coded to only display three items at a time - it measures the item height by dividing the list view's height by three ... so there isn't a practical way of doing what you want.
I suggest making the text font larger ...
I've got idea. Insert list into FrameLayout container. And by changing height of container list item height is changed. Result:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_centerInParent="true">
<android.support.wearable.view.WearableListView
android:id="#+id/wearable_list_game_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:dividerHeight="0dp"
android:scrollbars="none"/>
</FrameLayout>
</RelativeLayout>
Add one LinearLayout inside and set
android:layout_height="50dp"
android:layout_margin="5dp"
I've got a ListView with a customer ArrayAdapter and a custom ListItem-XML. At the bottom of this ListView I've added a FooterView with a Button. Now I want to get all the values of the three EditTexts in each of my ListItems when I click this Button.
Here below is my code:
activity_checklistresult.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
result_inner_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/item_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:id="#+id/tv_result_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin" />
<EditText
android:id="#+id/et_result_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin"
android:inputType="number" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="#+id/tv_result_product_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:layout_margin="#dimen/default_margin" />
<AutoCompleteTextView
android:id="#+id/actv_search_product"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:singleLine="true"
android:ellipsize="end"
android:layout_margin="#dimen/default_margin"
android:inputType="textAutoComplete" />
</LinearLayout>
<TextView
android:id="#+id/tv_result_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin" />
<EditText
android:id="#+id/et_result_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin"
android:inputType="numberDecimal" />
</LinearLayout>
ResultListActivity.java:
public class ChecklistResultActivity extends ListActivity
{
private MyResultAdapter adapt;
private Button confirmButton;
private ChecklistResultActivity rActivity;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checklistresult);
// Set my Custom ArrayAdapter for this ListActivity
setAdapter();
rActivity = this;
}
private void setAdapter(){
adapt = new MyResultAdapter(this, R.layout.result_inner_view, Controller.getInstance().getOrderedProducts());
setListAdapter(adapt);
// Add the confirm button at the end of the list
addFooterConfirmButton();
}
private void addFooterConfirmButton(){
ListView lv = (ListView)findViewById(android.R.id.list);
FrameLayout footerLayout = (FrameLayout) getLayoutInflater().inflate(R.layout.result_footer_view, null);
confirmButton = (Button)footerLayout.findViewById(R.id.confirm_result_button);
confirmButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
...
// Get all EditText values (and compare them with the Default Value)
}
});
lv.addFooterView(footerLayout);
}
...
MyResultAdapter.java:
public class MyResultAdapter extends ArrayAdapter<OrderedProduct>
{
private Context context;
private int layoutResourceId;
private LayoutInflater inflater;
public MyResultAdapter(Context c, int layoutResourceId, List<OrderedProduct> objects){
super(c, layoutResourceId, objects);
this.layoutResourceId = layoutResourceId;
this.context = c;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
if(view == null)
view = inflater.inflate(layoutResourceId, parent, false);
...
return view;
}
}
In the ResultListActivity at // Get all EditText values (and compare them with the Default Value) I want to loop through all the OrderedProducts and compare the default values of those, with the new filled-in values of the two EditTexts and the AutoCompleteTextView. So how can I get those values from within the onClick of the Footer-Button?
Thanks in advance for the responses.
Your adapter has to save text on change for each created EditText :
create a map to save values
Define and set a generic TextWatcher for every EditText
set a Tag on the editText (using its position or any
id you want) we'll use this tag as the key in the hashMap
create a method to retrieve the value for a given EditText
Adapter :
public class MyResultAdapter extends ArrayAdapter<OrderedProduct>
{
...
private HashMap<String, String> textValues = new HashMap<String, String>();
...
public ViewView getView(int position, View convertView, ViewGroup parent){
View view = convertView;
boolean convertViewWasNull = false;
if(view == null){
view = inflater.inflate(layoutResourceId, parent, false);
convertViewWasNull = true;
}
myEditText1 = findViewById...
myEditText2 = findViewById...
if(convertViewWasNull ){
//be aware that you shouldn't do this for each call on getView, just once by listItem when convertView is null
myEditText1.addTextChangedListener(new GenericTextWatcher(myEditText1));
myEditText2.addTextChangedListener(new GenericTextWatcher(myEditText2));
}
//whereas, this should be called on each getView call, to update view tags.
myEditText1.setTag("theFirstEditTextAtPos:"+position);
myEditText2.setTag("theSecondEditTextAtPos:"+position);
}
private class GenericTextWatcher implements TextWatcher{
private View view;
private GenericTextWatcher(View view) {
this.view = view;
}
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
public void afterTextChanged(Editable editable) {
String text = editable.toString();
//save the value for the given tag :
MyResultAdapter.this.textValues.put(view.getTag(), editable.toString());
}
}
//you can implement a method like this one for each EditText with the list position as parameter :
public String getValueFromFirstEditText(int position){
//here you need to recreate the id for the first editText
String result = textValues.get("theFirstEditTextAtPos:"+position);
if(result ==null)
result = "default value";
return result;
}
public String getValueFromSecondEditText(int position){
//here you need to recreate the id for the second editText
String result = textValues.get("theSecondEditTextAtPos:"+position);
if(result ==null)
result = "default value";
return result;
}
}
You can store all edittext values and get them when needed, you can store it in afterTextChange or onTextChange, it's up to you.
public class MyResultAdapter extends ArrayAdapter<OrderedProduct>{
...
private final String[] valueList;
public MyResultAdapter(Context c, int layoutResourceId, List<OrderedProduct> objects){
super(c, layoutResourceId, objects);
...
valueList = new String[objects.size()];
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
if(view == null)
view = inflater.inflate(layoutResourceId, parent, false);
...
//for edittext add text watcher listener
final pos = position;
editText.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) {
valueList[pos] = s.toString();
}
#Override
public void afterTextChanged(Editable s) {
}
});
return view;
}
public String[] getValueList(){
return valueList;
}
}