I have a list view with custom cell layout. Actually it shows data from a table, there are two button one for editing and the other is for deleting the record. these two buttons are hidden, when long click on the row then these two buttons shows up .
Here is the cell_layout :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Customer Code and Name "
android:textSize="16sp"
android:textColor="#ff000000" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginRight="25dp">
<TextView
android:id="#+id/txtCusCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cus code"
android:textSize="16sp"
android:textColor="#ff000000" />
<TextView
android:id="#+id/txtCusName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="cus Name"
android:textSize="16sp"
android:textColor="#ff000000"
android:layout_marginLeft="10dp" />
</LinearLayout>
<ImageView
android:id="#+id/imgbtnOrderActions"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/down"
android:layout_alignParentEnd="false"
android:clickable="true"
android:layout_alignParentRight="true"
android:background="#drawable/test"/>
</RelativeLayout>
<TableLayout
android:id="#+id/tblLayoutOrderAction"
android:layout_width="fill_parent"
android:layout_height="0dp">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<ImageView
android:id="#+id/lmgbtnOrderEdit"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:src="#drawable/edit"
android:layout_weight="1"
android:layout_column="1"
android:clickable="true"
android:background="#ff00b4df" />
<ImageView
android:id="#+id/ImgbtnOrderDelete"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:src="#drawable/delete"
android:layout_weight="1"
android:layout_column="2"
android:background="#ffff625a"
android:clickable="true" />
</TableRow>
</TableLayout>
</LinearLayout>
those two buttons are in Table Layout i give them 0dp height fro hiding them.
And this is OnLongItemClick event of listView :
lstviewOrders.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener()
{
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l)
{
final TableLayout tblLay = (TableLayout) view.findViewById(R.id.tblLayoutOrderAction);
TableLayout.LayoutParams lay = new TableLayout.LayoutParams(30, ViewGroup.LayoutParams.MATCH_PARENT);
tblLay.setLayoutParams(lay);
return false ;
}
});
Here comes the problem . When an item in listview is long clicked then it shows the edit and delete button of that items but it also shows those button in the item which is at next 7th position . For example if i click item on position 3 then button of 3,10,17,.... are also showed ...
how to get ride of this problem ???
This sounds to me like you're dealing with the ListView's view recycling feature. This answer provides a great explanation.
Basic example: if a ListView has a total of 20 items but only enough room to show 4 on screen at the same time, then the ListView will only use 4 view objects but recycle them for each item in the list. So if you change something on view 2, then scroll down you'll find that this change also applied to view 6. This is what makes dynamic views difficult with ListViews.
In the above example, if your adapter is loading view 6, in your adapter's getView method, the convertView object is the view from 2, which is then repurposed for data element 6. I would play around with storing whether the buttons are shown in your data and resetting the convertView in this method and then showing/hiding the buttons based on the underlying data.
ListViews handle focus on displaying underlying data, but not necessarily editing that data in a view.
You could try skipping the part of your getView that tries to use the convertView so that you're always making a new view, but I'm found this can cause some other unexpected UI experiences. Good luck!
The problem is occuring because listview cells are reusing.
And when you are showing the button for a particular cell and scroll the list view then the item which is reusing that cell will also show the buttons.
To avoid the problem what you can do is take a position in adapter by any int variable and update the posion on long press in adapter.
In getView method of adapter put the position check if items are having same postion will show the button else it will set visibilty GONE.
Like in adapter : -
int selectedposition = -1;
public View getView(.........){
// your code
if (position == selectedposition){
button.setVisibility(VISIBLE);
}
else{
button.setVisibility(GONE);
}
return convertedView;
}
Related
I am trying to make a periodic table app.
RecyclerView was used to display items in listed fashion.
When an item is clicked then the hidden layout which contains element details changes from View.GONE to View.VISIBLE.
Problem is that when I click 1st item and then scroll then every 11th item is opened (11,21,31..) and when closed every 11th item is closed.
Code for hiding and unhiding the details layout:
holder.element_single_card.setOnClickListener {
if(holder.hidden_elements.visibility == View.GONE) {
holder.hidden_elements.visibility = View.VISIBLE
}
else{
holder.hidden_elements.visibility = View.GONE
}
}
Code of Parent Layout containing all text views for showing details of element
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/element_hidden_information"
android:visibility="gone"
android:layout_below="#id/element_shown_information"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/element_symbol"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/element_period"
android:layout_below="#id/element_symbol"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/element_mass"
android:layout_below="#id/element_period"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/element_density"
android:layout_below="#id/element_mass"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/element_boiling_point"
android:layout_below="#id/element_density"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/element_melting_point"
android:layout_below="#id/element_boiling_point"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/element_electron_affinity"
android:layout_below="#id/element_melting_point"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/element_summary"
android:layout_below="#id/element_electron_affinity"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>
How can I stop every 11th item from opening and what is the problem with my code?
Ideally, you should have a Boolean type isExpanded variable in your model along with getter/setter methods.
This variable will be responsible for storing the expanded state corresponding to each item.
From onClick call -
myModel.setIsExpanded(true);
and write below code in onBindViewHolder()
if(myModel.getIsExpanded())
{
holder.hidden_elements.visibility = View.VISIBLE
}
else
{
holder.hidden_elements.visibility = View.GONE
}
Since RecyclerView reuses it's viewHolder objects, you can't rely on the earlier state of the View.
Let me know if you need any more clarification :)
This is because when you scroll down the 11th element is reusing the same view as the 1st element(this is a desired android feature due to memory constraints) you need to reset the layout to View.GONE if the element you are trying to display is not in open state.
To do this you cannot rely on the view's current state as you are doing in OnClickListener and should instead maintain a state of selected or clicked in the list item itself that you are using to display the data.
Further documentation about view recycling can be found in the official Android docs.
I am trying to put a custom listView into a scrollView and when I scroll down and up I lose the top items in the listView which are a TextView and a CheckBox for some reason.
Here's my code:
activity_program.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/tv_program_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.10"
android:text="Program name"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/tv_program_info"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_weight="0.20"
android:text="program info, talk abt sets, reps, weight etc..." />
<ListView
android:id="#+id/android:list"
android:layout_width="match_parent"
android:layout_height="395dp" >
</ListView>
<Button
android:id="#+id/bt_savework"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.10"
android:text="Save Workout" />
</LinearLayout>
My custom listView contains these:
<?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"
android:padding="5dp" >
<TextView
android:id="#+id/tv_exercice_title"
android:layout_width="270dp"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/cb_exercicedone"
android:layout_alignParentTop="true"
android:gravity="center_vertical"
android:text="Exercice title"
android:textAppearance="?android:attr/textAppearanceMedium" />
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_below="#+id/tv_exercice_title"
android:orientation="horizontal" >
<CheckBox
android:id="#+id/cb_setdone"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="7dp"
android:text="Set" />
<TextView
android:id="#+id/tv_set_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="3dp"
android:text="1" />
<TextView
android:id="#+id/tv_reps"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:text="Reps x" />
<EditText
android:id="#+id/et_reps_number"
android:layout_width="47dp"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number" />
<TextView
android:id="#+id/tv_weight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:text="Weight" />
<EditText
android:id="#+id/et_weight_number"
android:layout_width="65dp"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number" />
<TextView
android:id="#+id/tv_kgorlbs"
android:layout_width="59dp"
android:layout_height="wrap_content"
android:text="kg/lbs"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<CheckBox
android:id="#+id/cb_exercicedone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignRight="#+id/linearLayout1" />
</RelativeLayout>
In my ListActivity I use a custom adapter to fill the ListView with the above template and only edit the tv_set_number (for now) then set the tv_exercice_title's visibility to "gone" to add more sets.
If you think the problem could be in my java code let me know in the comment and I will post it.
Please tell me what's the problem.
Here's some screenshots:
Before I scroll:
image 1
After I scroll:
image 2
Seems to me you are using the ListView to generate different kinds of rows and you're missing some steps. You could also consider to rethink the structure, as maybe this would better fit into a ExpandableListView: from the screenshots you post seems like you'd have a set of rows that hierarchically belong to a group view.
The ExpandableListView would fit this purpose, and also allow to collapse/expand the groups. I'd take a look at it, it's really easy, you'd only have to make the adapter descend from ExpandableListViewAdapter and provide methods to obtain the Group views (Your title & checkbox) and the item views (the sets with reps, weight, etc...)
If, on the contrary, you want to make it with a ListView, there are some issues to care about (I'll call TITLE ROWS to those with the title & checkbox, and regular rows to the regular ones)
What is happening now is, when you create a view and this view is not a TITLE ROW, you are setting the visibility of the title to GONE. But if you scroll, ie., DOWN and a TITLE row has to appear from the upper edge, the View you are given to recycle is the one that just left the screen by the lower edge, that was probably a REGULAR ROW. So in getView() you not only have to set Visibility to GONE for regular rows, but also back to VISIBLE for Title Rows. Google an explanation on how View recycling works for ListView and you'll understand it right away.
ListView provides a mechanism to help in these cases: The View Types:
You declare 2 "row types" overriding getViewTypeCount() and getItemViewType(int position) in your adapter. Type 0 will be TITLE ROWS, and Type 1 would be REGULAR ROWS.
In getView / convertView you'll generate / reuse the 2 different views separately based on the type.
.
#Override
public int getViewTypeCount() {
return 2; // you have 2 different types
}
#Override
public int getItemViewType(int position) {
if (position IS A TITLE ROW) return 0; else return 1;
}
... and then in getView() {
if (getItemViewType(position) == 0) {
// it's a TITLE ROW, create / reuse it accordingly
} else {
// it's a REGULAR ROW, create / reuse it accordingly
}
This has the advantage that ListView does some of the dirty work for you, so you'll be given the correct view type to recycle.
I've got a ListView with a custom Adapter inheriting from ArrayAdapter. I'm using a custom Checkable subclass of LinearLayout to highlight the last selected item in the list where it basically maps the checked state to selected.
The layout used by the Adapter for list items is as follows:
<com.wordlistdictionary.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="40dp">
<LinearLayout
android:id="#+id/entry_text"
android:layout_width="0dp"
android:layout_weight="7"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:duplicateParentState="true"
/>
<TextView
android:id="#+id/entry_number_of_occurences_1"
android:textSize="9pt"
android:typeface="monospace"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="#color/item_text_color_selector"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:duplicateParentState="true"
/>
<TextView
android:id="#+id/entry_frequency_1"
android:textSize="9pt"
android:typeface="monospace"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="#color/item_text_color_selector"
android:layout_gravity="center_vertical"
android:layout_weight="2"
android:duplicateParentState="true"/>
<ImageButton
android:id="#+id/delete_entry_button_1"
android:src="#drawable/delete_button_selector"
android:layout_height="40dp"
android:layout_width="40dp"
android:layout_gravity="center_vertical"
android:layout_marginRight="15dp"
android:duplicateParentState="true"
/>
</com.wordlistdictionary.CheckableLinearLayout>
It works as I expect it with the text color changing for the last touched item until I'm adding the last ImageButton view and it stops highlighting the text from that point.
Has anybody encountered this and what was your solution?
Currently I'm thinking of a workaround with manually propagating the selected state to all child views from my custom layout as opposed to just changing the selected state of the layout view itself and relying on the duplicateParentState mechanism.
It turns out when added to a list item a Button or ImageButton "swallows" the touched event so it doesn't propagate to the list view so I had to set imageButton.setTouchable(false) in getView() in my custom Adapter.
Note that I first tried to set android:touchable='falase' in my layout file but it didn't work so I had to set it programmatically.
I've found the answer in these 2 SO questions:
ListView setOnItemClickListener not working by adding button
Click is not working on the Listitem Listview android
I had set up an Activity and a Fragment, and in the layout I had a ListView, which I gave an arbitrary name and accessed via findViewById(). All was working fine, until I noticed that scrolling didn't work for the ListView.
There are many threads here on SO about ListView and lack of scrolling. I used much more time than I care to admit trying out one possible solution after another. Nothing worked, until I stumbled upon the solution, which I'll describe in an answer to this question.
EDIT:
I've deleted the answer I posted to my own question, where I claimed that you had to use ListFragment (or SherlockListFragment) to get scrolling of a ListView to work.
Thanks to Zackehh9lives I've determined that I was wrong in that claim.
The key phrase in his answer is that the stump of code he shows is in the onCreateView() method. After some experimenting, I think the situation is as follows:
If you use ListFragment (or SherlockListFragment) you have to set up the ListView widget in the onActivityCreated() method, and ListView scrolling works.
If you use Fragment (or SherlockFragment) you can set up ListView in onActivityCreated() or in onCreateView(), but if you do it in onActivityCreated() then scrolling doesn't work.
That was my problem - I was using SherlockFragment and setting up ListView in onActivityCreated().
I have a ListView in a SherlockFragment and it scrolls just fine. Not sure what the issue is? Perhaps you just have a something incorrect somewhere (might want to post your code?). Below is my ListView and XML:
MyFragment.java:
// Find the ListView we're using
list = (ListView)view.findViewById(R.id.listView);
// Set the vertical edges to fade when scrolling
list.setVerticalFadingEdgeEnabled(true);
// Create a new adapter
adapter = new ArrayAdapter<String>(getActivity(), R.layout.list_item, R.id.title, questions);
// Set the adapter to the list
list.setAdapter(adapter);
// Set on item click listener to the ListView
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// Do stuff
}
});
All that code is all I have related to my ListView in the Fragment, and it's in my onCreateView(). Below is the XML for it.
ListItem.xml:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_toLeftOf="#+id/arrow"
android:orientation="vertical" >
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:text="#string/title"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="#+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/title"
android:layout_alignParentBottom="true"
android:layout_below="#+id/title"
android:layout_marginTop="5dp"
android:padding="2dp"
android:text="#string/date"
android:textColor="#7F7F7F"
android:textSize="12sp" />
</RelativeLayout>
<ImageView
android:id="#+id/arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:contentDescription="#string/app_name"
android:src="#drawable/arrow_next" />
ListView.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:baselineAligned="false"
android:paddingTop="-2dp" >
<ListView
android:id="#+id/listView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" >
</ListView>
</LinearLayout>
If you post your code, we have a better chance at helping :)
In my android application I have a listview which displays dynamic data according to the user query.
The problem is I need to display in the footer, which Item the user currently have selected(while Scrolling through the listview).
I Implemented OnItemSelectedListener and can catch the scrolling position.
I initially defined a global variable and asigned it to -1.
int selectedRowIndex = -1;
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
selectedRowIndex = arg2;
footer.setText(String.valueOf(selectedRowIndex+1)+ " of " + String.valueOf(companyList.size()));
}
The problem is, when the page initially load and even no item have yet selected(Scroll), the selectedRowIndex value had become 0(The first Item in the listview). I cant understand why it happen and can anyone suggest a way to implement this .
Thanks inadvance
Edits
<RelativeLayout android:id="#+id/relativeLayout1" android:layout_height="wrap_content" android:layout_width="match_parent">
<TextView android:text="TextView"
android:id="#+id/noCompanysFound_Message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:textStyle="italic"
android:layout_marginTop="10dp">
</TextView>
<ListView android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/companylistView"
android:listSelector="#drawable/item_focus_bkg"
android:layout_above="#+id/footer_linearLayout"
android:focusable="false">
</ListView>
<LinearLayout android:id="#+id/footer_linearLayout" android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" android:layout_alignParentBottom="true" android:background="#drawable/bottom_bkg" android:gravity="center_horizontal">
<TextView android:text="Footer Text"
android:id="#+id/companylistFooterTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF">
</TextView>
</LinearLayout>
</RelativeLayout>
I think whenever your activity created your listview get Focused and the first row will be selected that's why listview's onItemSelected() will be surely called once and the index of first row of list is 0 so in code
selectedRowIndex = arg2; became selectedRowIndex = 0;
If I am wrong then give me suggestion or let me know.