I want to make a listview unselectable and unclickable. I'm talking about the color change that occurs when I click on a list item. The code is given below. I'm a newbie in android so please be kind.
from : listitem.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="8px">
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"/>
<TextView
android:id="#+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16px"/>
</LinearLayout>
from : details.java
TestActionAdapter() {
super(TestDetails.this, R.layout.action_list_item, actions);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TestAction action = actions.get(position);
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.action_list_item, parent, false);
TextView label = (TextView) view.findViewById(R.id.label);
label.setText(action.getLabel());
TextView data = (TextView) view.findViewById(R.id.data);
data.setText(action.getData());
return view;
}
Check out the answer here:
How to disable list items...
Basically extend ArrayAdapter, and add these 2 functions:
#Override
public boolean areAllItemsEnabled() {
return false;
}
#Override
public boolean isEnabled(int position) {
return false;
}
If all you want is to prevent all rows highlighting on click just use ListView android:listSelector="#android:color/transparent"
When you return view from getView(..) Method, just put in view.setEnabled(false) before return view .
Related
I'm trying to make a slight adjustment to the positioning of the selected item in the spinner. Not the dropdown list items, as I already have a custom view in my adapter for that, but the selected item specifically.
As you can see in the screenshot, "Any" is the currently selected item. But it is aligned oddly within the container because it has to accommodate the longest string in the dropdown, which is "Dark Purple Burnt Sienna" (or whatever). I want to align the selected text to the right so that "Any" is next to the dropdown indicator instead of way out in the middle.
I've attempted to make adjustments to my custom spinner-item view, but it doesn't have any affect on the selected item.
I've also attempted to set gravity and text alignment on the Spinner itself, but it has no effect.
Here's the image and the xml:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/default_black"
android:layout_centerVertical="true"
android:text="Color" />
<Spinner
android:id="#+id/spn_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"/>
</RelativeLayout>
Edit: Here's my adapter:
public class ColorsAdapter<T> implements SpinnerAdapter {
ArrayList<String> mColors;
ArrayList<Integer> mValues;
Context mContext;
public ColorsAdapter(ArrayList<String> colors, ArrayList<Integer> values,
Context context) {
mContext = context;
mColors = colors;
mValues = values;
}
#Override
public int getCount() {
return mColors.size();
}
#Override
public Object getItem(int position) {
return mColors.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return R.layout.list_item_color;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(mContext);
v.setText(mColors.get(position));
return v;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE );
View row = inflater.inflate(getItemViewType(position), parent, false);
TextView tvName = (TextView)row.findViewById(R.id.tv_name);
tvName.setText(mColors.get(position));
row.setTag(mValues.get(position));
return row;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isEmpty() {
return false;
}
}
And here's the XML for the list item:
<TextView
android:id="#+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:gravity="right"/>
You can adjust the settings for selected item in getView(int position, View convertView, ViewGroup parent) method. If you just want to set the gravity and text alignment, you should set it to the TextView in the method like
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(mContext);
v.setText(mColors.get(position));
v.setGravity(Gravity.END); // OR v.setGravity(Gravity.RIGHT);
return v;
}
Or you can simply inflate custom layout if you want to make further customization:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View row = null;
if (inflater != null) {
row = inflater.inflate(R.layout.list_item_view_color, parent, false);
TextView textView = row.findViewById(R.id.textview);
textView .setText(mColors.get(position));
}
return row;
}
Where list_item_view_color.xml is your layout file for the selected value.
(NOTE: If you want to use options like autoSizeTextType, you can use them with app prefix for AppCompatTextView in xml files)
Simple solution would be to build another Custom view for the spinner TextView layout, and specify the gravity for your TextView in that. Something like :
<!--spinner_layout.xml (in 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="wrap_content"
android:gravity="right"
/>
Use that in initalising the ArrayAdapter of your spinner :
ArrayAdapter<String> adapter = new ArrayAdapter<String>
(this, android.R.layout.spinner_layout,
spinnerArray);
UI output :
You can creating the TextView for the getView method programmatically so no property for alignment is being set, easy thing to do is inflate it in the same way you are doing it on the getDropdownView, or simply set the proper gravity in the view you are instantiated.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(mContext);
v.setText(mColors.get(position));
v.setGravity(Gravity.RIGHT);
return v;
}
You can try this
android:autoSizeTextType="uniform"
Padding, Margins and Alignments get confusing when it comes to Spinners. I ran into a similar issue as well. But for me I wasn't using a custom view and adapter, so I managed to use styles to get around this issue.
For you since you are already using custom view and adapter, you can make the background null for the spinner so that the dropdown arrow will not be visible.
android:background="#null"
Then in the TextView, you can assign drawableRight to be the dropdown arrow.
android:drawableRight="#drawable/ic_spinner_drop_arrow_white_24dp"
The icon can be a dropdown vector drawable. Also to specify particular margin between the arrow and text, you should be able to use drawablePadding
Hope this helps.
I can give you a method that may work.
In XML
1) add a new text view called the_current_color text view
2) allign this text view above the spinner and to the start of the arrow icon
or wherever you want it to be.
In your code
1) when you listen to (on item selected ) from the spinner simply get the current text and set it in the (the_current_color) text view.
2) and try to hide the texts in the spinner by changing color to transparent.
Hope it works
Edit
I might also suggest something maybe it changes things
lets say that we have a spinner that uses this string resource file to populate its adapter
<string-array name="my_adapter">
<item>Blue </item>
<item>Red</item>
</string-array>
until now we have a spinner that shows (red item) and (blue item) at the far left from the arrow icon of the spinner.
create another string resources now like that
<string-array name="my_adapter_two">
<item> Blue </item>
<item> Red</item>
</string-array>
as you can see now the added space will give an illusion that the strings are beside the arrow icon
you can add space that fit your need and you can maybe switch the files after you click a certain item and then switch them back.
You can try the following Custom view.
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textView1"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="right"
android:padding="15dp"
android:textAlignment="gravity"
android:textColor="#color/black"
android:textSize="10dp" />
I've adapted the standard ExpandableListView to use my own indicator image so I can remove it when a group has no children. I also made some changes that the text views in the group view have a separate OnClickListener to show some details about the group. Clicking on the indicator icon will expand/collapse the group as usual.
My question is how do I get the same visual feedback (shift in background color to blue and back) on clicking the text views of a group as I get when clicking the indicator icon or a child row?
My group layout is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="5dp" >
<TextView
android:id="#+id/news_group_timestamp"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="#+id/news_group_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingRight="5dp" />
<ImageView
android:id="#+id/news_group_exp_indicator"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="#drawable/news_group_expander" />
</LinearLayout>
The relevant portions of the adapter are listed below. The ViewHolder is a simple class to support various group types (section header or actual group item).
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
{
convertView = createGroupView(groupPosition);
fillGroupView(groupPosition, isExpanded, convertView);
return convertView;
}
protected class OnTextClickListener implements OnClickListener
{
protected int m_groupPosition;
public OnTextClickListener(int groupPosition)
{
m_groupPosition = groupPosition;
}
#Override
public void onClick(View v)
{
...
}
}
protected View createGroupView(int groupPosition)
{
View view = m_inflater.inflate(R.layout.news_group, null);
ViewHolder holder = new ViewHolder();
holder.groupExpIndicator = (ImageView) view.findViewById(R.id.news_group_exp_indicator);
// We set the OnClickListener for the timestamp and title views so we
// can use this to show the details of a group item. The expansion of
// the group is handled higher up where the indicator click is
// processed.
holder.groupTimestampView = (TextView) view.findViewById(R.id.news_group_timestamp);
holder.groupTimestampView.setOnClickListener(new OnTextClickListener(groupPosition));
holder.groupTitleView = (TextView) view.findViewById(R.id.news_group_title);
holder.groupTitleView.setOnClickListener(new OnTextClickListener(groupPosition));
view.setTag(holder);
return view;
}
I have listview that I have populated into a alertDialog When the alertDialog displays the user are able to click on these items in the listview and that is when the problem comes in. I do not want the user to be able to click on the items in the listview and I have already tried adding this to my xml layout android:clickable="false" and android:focusable="false" but I am still getting the same results. Can somebody assist me with this issue that having.
Here is my base adapter class:
public class MyAdapter extends BaseAdapter {
final String[] listItemsFirstRow = {"Item1","Item2"};
final String[] listItemSecondRow = {"Item1", "Item2"};
#Override
public int getCount() {
return listItemsFirstRow.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null)
{
LayoutInflater layoutInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.twolinelistview, null);
}
((TextView)convertView.findViewById(R.id.text1)).setText( listItemsFirstRow[position]);
((TextView)convertView.findViewById(R.id.text2)).setText( listItemSecondRow[position]);
return convertView;
}
}
And here is my xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center_vertical"
android:paddingLeft="15dip"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:textAppearance="?android:attr/textAppearanceMedium"
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false" />
<TextView
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false" />
</LinearLayout>
Modify your BaseAdapter to override isEnabled to tell the ListView that the items aren't clickable.
Example:
#Override
public boolean isEnabled(int position) {
return false;
}
Note that the documentation says this will do exactly what you want:
Returns true if the item at the specified position is not a separator. (A separator is a non-selectable, non-clickable item)
Try setting android:clickable="false" and android:longClickable="false" for your ListView in XML, or you can set it before you set the adapter as well. That should be enough to disable it, but if not android:focusable="false" and android:enabled="false" should definitely do it.
If you are just trying to prevent items from being highlighted another option is to change how it displays selected items and ignoring the events. One way that was suggested in an older question is:
android:listSelector="#android:color/transparent"
android:cacheColorHint="#android:color/transparent"
I am new to android and am trying to create two fragments and have it so you can slide between the two, one is a list and the otehr a grid. I had the list working when it when I was using an ArrayAdapter and had my EventListFragment extending ListFragment (if code is helpful let me know and ill post that part)
I am now trying to create a custom list view with multiline list items (let me know if there is an easier way and if i have simply overcomplicated the whole thing)
Here is my code:
Event List Fragment:
public class EventListFragment extends Fragment {
ArrayList<EventObject> eventObjects;
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
eventObjects = ((EventsActivity)getActivity()).getEventObjects();
View view = inflater.inflate(R.layout.eventgrid ,container,false);
Listview listView = (ListView) view.findViewById(R.id.listView);
if (listView == null) {
System.out.println("asas");
}
listView.setAdapter(new MyCustomBaseAdapter(getActivity().getBaseContext(), eventObjects));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
Object o = listView.getItemAtPosition(position);
EventObject fullObject = (EventObject)o;
System.out.println("asd");
}
});
return view;
}
}
The corresponding xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<ListView
android:id="#+id/listView"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
</RelativeLayout>
The xml for the customgridrow:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/name"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="#FFFF00"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="#+id/cityState"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="#+id/phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
EDIT
The getView() from MyCustomBaseAdapter :
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.customgridrow, null);
holder = new ViewHolder();
holder.txtName = (TextView) convertView.findViewById(R.id.name);
holder.txtCityState = (TextView) convertView.findViewById(R.id.cityState);
holder.txtPhone = (TextView) convertView.findViewById(R.id.phone);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtName.setText(events.get(position).getName());
holder.txtCityState.setText(events.get(position).getDate());
holder.txtPhone.setText(events.get(position).getVenue());
return convertView;
}
From your comments
You are inflating the wrong layout
You should inflate the one that has listview and initialize the same.
Change
View view = inflater.inflate(R.layout.eventgrid ,container,false);
to
View view = inflater.inflate(R.layout.eventList ,container,false);
Every time you want to add an object to a list, you have to provide a view for the object. Android asks your list adapter, be it custom or system-defined, it asks the adapter what each list item is supposed to look like. This is where getView() comes into play.
public abstract View getView (int position, View convertView, ViewGroup parent):
Get a View that displays the data at the specified position in the data set.
If convertView is null, you will get an NPE.
Tutorials here: http://www.javacodegeeks.com/2013/06/android-listview-tutorial-and-basic-example.html
I made a custom Listview (Without overriding getView() method) with each item in a Listview having a following Layout
contactlayout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" android:weightSum="1">
<CheckBox android:id="#+id/checkBox1" android:text="CheckBox" android:layout_width="134dp" android:layout_height="108dp" android:focusable="false"></CheckBox>
<LinearLayout android:id="#+id/linearLayout1" android:layout_height="match_parent" android:orientation="vertical" android:layout_width="87dp" android:layout_weight="0.84" android:weightSum="1" >
<TextView android:text="TextView" android:layout_height="wrap_content" android:layout_width="match_parent" android:id="#+id/name" android:layout_weight="0.03"></TextView>
<TextView android:text="TextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="#+id/phone"></TextView>
<TextView android:text="TextView" android:layout_height="wrap_content" android:layout_weight="0.03" android:layout_width="match_parent" android:id="#+id/contactid" android:visibility="invisible"></TextView>
</LinearLayout>
</LinearLayout>
I am populating the Listview using a SimpleCursorAdapter in a following way...
Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
String from[] = new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone.CONTACT_ID};
int to[] = new int[]{R.id.name,R.id.phone,R.id.contactid};
SimpleCursorAdapter s = new SimpleCursorAdapter(this,R.layout.contactlayout,c,from,to);
lv.setAdapter(s);
On Click of a button I am reading the states of all the Checkboxes. The problem is, if I check one CheckBox several others down the line get automatically Checked. I know this is reusing of Views. How do I avoid it ?. I am not even overriding getView() method in this case, so I wonder if there is still any way to achieve what I want?
Answer
Finally I implemented what #sastraxi suggested...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
final CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkBox1);
final TextView name = (TextView) view.findViewById(R.id.name);
final TextView contactId = (TextView) view.findViewById(R.id.contactid);
final int pos = position;
checkBox.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
if(checkBox.isChecked())
{
checkList.add(String.valueOf(pos));
nameList.add(name.getText().toString());
contactList.add(contactId.getText().toString());
Log.i("Chk added",String.valueOf(pos));
}
else
{
checkList.remove(String.valueOf(pos));
nameList.remove(name.getText().toString());
contactList.remove(contactId.getText().toString());
Log.i("Un Chk removed",String.valueOf(pos));
}
}
});
if(checkList.contains(String.valueOf(pos)))
{
checkBox.setChecked(true);
}
else
{
checkBox.setChecked(false);
}
return view;
}
another way to force not reusing the views, add the following in your cursor adapter:
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public int getViewTypeCount() {
return 500;
}
but yes, you should reuse views whenever possible. In my particular case, I am adding images to my views and without forcing to not reuse the view, they would get re-rendered in the reused views.
Ah, I see what the problem is.
Make a new class that extends SimpleCursorAdapter, say CheckboxSimpleCursorAdapter, and override getView as such:
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.CheckBox1);
checkBox.setChecked(getIsThisListPositionChecked(position));
return view;
}
As you're not using a layout whose top-level View implements Checkable, you have to do everything yourself. That includes clearing state (in this case), as the default implementation re-used a View that was checked--as you correctly intuited.
Edit: use this new code, and implement a protected boolean getIsThisListPositionChecked(int position) method that returns whether or not the item is currently checked (or something like that). I hope I'm being clear enough--you need to figure out if the item should be checked according to your model, and then set that when you create the View.
It's always better to re-use views. What you are trying to achieve can be done with a few tweaks in your code. You need to record the checkedness of your checkboxes by using aanother variable list (a boolean for each list item).
Override these two methods in your Adapter class
#Override
public int getViewTypeCount()
{
return getCount();
}
#Override
public int getItemViewType(int position)
{
return position;
}