I want to add gradient for each row. What I've tried to do is on listview label put this attribut, android:background="#drawable/mygradient". But All I get is this gradient displayed all along the list. What I want is this gradient to be displayed for each item.
Thanks in advance
You can provide a custom adapter for your list view and set the gradient as the background in its getView method. Something like this:
public class MyAdapter extends BaseAdapter {
List<MyDataType> myData;
Context context;
public MyAdaptor(Context ctx, List<MyDataType> myData) {
this.myData = myData;
this.context = ctx;
}
public int getCount() { return myData.size() };
public Object getItem(int pos) { return myData.get(pos); }
public long getItemId(int pos) { return 0L; }
public View getView(int pos, View convertView, ViewGroup parent) {
//this is where you can customise the display of an individual
//list item by setting its background, etc, etc.
...
//and return the view for the list item at the end
return <List item view>;
}
}
Then you can set this adapter as the adapter for your list:
ListView myList = <initialise it here>
myList.setAdapter(new MyAdapter(getContext(), listData);
Now whenever a list item needs to be displayed, getView method will be called, where you'll perform all the necessary display customisation, including setting the background.
Instead of setting background property set Selector of list, as below:
android:listSelector="#drawable/list_selector_background"
Related
Highlighted item changes position when scrolling listview. If i choose first item in listview and scrolling to the end, between every 7-8 item is selected. And even highlighted item lose its position and highlighting 3rd item. i dont use custom adapter for listview, only for textview. Here is code:
lv=(ListView) findViewById(R.id.listView);
myadaptersong = new ArrayAdapter<String>(this, R.layout.custom_item, R.id.menu, music);
lv.setAdapter(myadaptersong);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(menuItem != null) menuItem.setBackgroundColor(Color.parseColor("#ffffff"));
menuItem = view;
menuItem.setBackgroundColor(Color.parseColor("#a2aed3"));
});
}
UPDATE:
Custom Adapter is this
public class CustomAdapter extends BaseAdapter {
String music[];
int flag[];
LayoutInflater inflater;
public CustomAdapter(Context context, String[]music, int []flag)
{
this.music=music;
this.flag=flag;
inflater=(LayoutInflater.from(context));
}
#Override
public int getCount() {
return music.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View view, ViewGroup viewGroup) {
view=inflater.inflate(R.layout.custom_item,viewGroup,false);
TextView name= (TextView)view.findViewById(R.id.menu);
name.setText(music[position]);
return view;
}
}
what should i do here?
The code you posted won't work the way you intend (as you already noticed). Let's say your ListView shows 4 items on screen and you clicked on the first item (item 0, highlighting it by changing its background color). When you scroll down to see more views and item 0 goes off the screen, the view from item 0 will be recycled to show a later item (say, item 6).
Now item 6 is using the view whose background color you already changed, so it will be highlighted. As the view continues to go off-screen and be re-used, other random rows in the ListView will be highlighted.
You will need to implement a custom adapter to do what you are trying to do.
I'm trying to make a simple to-do list where you would long-press an item to mark it as 'done', in which case it will be greyed out and strikethrough.
I'm working on the strikethrough first and found some sample code here creating a strikethrough text in Android? . However the problem is that the setPaintFlags() method only seems to work on TextView whereas the items on my list are String. I can't cast a String to a TextView, and I found a workaround here but apparently it's highly discouraged to do it: Cast String to TextView . Also I looked up SpannableString but it doesn't seem to work for strings of varying length.
So I'm back at square one - is it at all possible to implement what I'm trying to do? Or will I have to store my list items differently instead?
Relevant code:
public class MainActivity extends ActionBarActivity {
private ArrayList<String> items;
private ArrayAdapter<String> itemsAdapter;
private ListView lvItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Setting what the ListView will consist of
lvItems = (ListView) findViewById(R.id.lvItems);
readItems();
itemsAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items);
lvItems.setAdapter(itemsAdapter);
// Set up remove listener method call
setupListViewListener();
}
//Attaches a long click listener to the listview
private void setupListViewListener() {
lvItems.setOnItemLongClickListener(
new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter,
View item, int pos, long id) {
// Trying to make the onLongClick strikethrough the text
String clickedItem = items.get(pos);
//What do I do here??
// Refresh the adapter
itemsAdapter.notifyDataSetChanged();
writeItems();
// Return true consumes the long click event (marks it handled)
return true;
}
});
}
Let's take a step back and consider your app. You want to show a list of jobs to the user. Each job has a description. And each job has two possible states: 'done' or 'not done'.
So I would like to introduce a class 'Job'
class Job
{
private String mDescription;
private boolean mDone;
public Job(String description)
{
this.mDescription = description;
this.mDone = false;
}
// ... generate the usual getters and setters here ;-)
// especially:
public boolean isDone()
{
return mIsDone;
}
}
This way your ArrayList 'items' becomes be a ArrayList< Job >. Wether a job is done or not will be stored together with its description. This is important because you want to show the current state of the job to the user by changing the look of the UI element, but you need to keep track of the job's state on the data level as well.
The UI element - the TextView - will be configured to present information about the job to the user. One piece of information is the description. The TextView will store this as a String. The other piece of information is the state (done/ not done). The TextView will (in your app) store this by setting the strike-through flag and changing its color.
Because for performance reasons a ListView uses less elements than the data list ('items') contains, you have to write a custom adapter. For brevity's sake, I'm keeping the code very simple, but it's worth the time to read up on the View Holder pattern:
Let's use a layout file 'mytextviewlayout.xml' for the list rows:
<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:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="#+id/textView"/>
</LinearLayout>
Now the code for the adapter looks like this:
EDIT changed from ArrayAdapter to BaseAdapter and added a view holder (see comments):
public class MyAdapter extends BaseAdapter
{
private ArrayList<Job> mDatalist;
private int mLayoutID;
private Activity mCtx;
private MyAdapter(){} // the adapter won't work with the standard constructor
public MyAdapter(Activity context, int resource, ArrayList<Job> objects)
{
super();
mLayoutID = resource;
mDatalist = objects;
mCtx = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = mCtx.getLayoutInflater();
rowView = inflater.inflate(mLayoutID, null);
ViewHolder viewHolder = new ViewHolder();
viewHolder.tvDescription = (TextView) rowView.findViewById(R.id.textView);
rowView.setTag(viewHolder);
}
ViewHolder vholder = (ViewHolder) rowView.getTag();
TextView tvJob = vholder.tvDescription;
Job myJob = mDatalist.get(position);
tvJob.setText(myJob.getJobDescription());
if (myJob.isDone())
{
// apply changes to TextView
tvJob.setPaintFlags(tvJob.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
tvJob.setTextColor(Color.GRAY);
}
else
{
// show TextView as usual
tvJob.setPaintFlags(tvJob.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
tvJob.setTextColor(Color.BLACK); // or whatever is needed...
}
return rowView;
}
#Override
public int getCount()
{
return mDatalist.size();
}
#Override
public Object getItem(int position)
{
return mDatalist.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
static class ViewHolder
{
public TextView tvDescription;
}
}
Due to the changed adapter,
in the MainActivity, you have to declare 'items' and 'itemsAdapter' as follows:
private ArrayList<Job> items;
private MyAdapter itemsAdapter;
...and in your 'onCreate()' method, you write:
itemsAdapter = new MyAdapter<String>(this, R.layout.mytextviewlayout, items);
Don't forget to change the 'readItems()' and 'writeItems()' methods because 'items' now is a ArrayList< Job >.
Then, finally, the 'onItemLongClick()' method:
EDIT use 'parent.getItemAtPosition()' instead of 'items.get()', see comments
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
{
// items.get(position).setDone(true);
Object o = parent.getItemAtPosition(position);
if (o instanceof Job)
{
((Job) o).setDone(true);
}
// and now indeed the data set has changed :)
itemsAdapter.notifyDataSetChanged();
writeItems();
return true;
}
I have implemented an ArrayAdapter for customizing a GridView. The layout of each item is defined in xml code that produce something like this:
In my Activity I have implemented the following code:
GridView gridview = (GridView) findViewById(R.id.gridview);
adapter = new myArrayAdapter(this, articlesList);
gridview.setAdapter(new myArrayAdapter(this, articlesList));
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
// here I want to change the text of the `TextView` in the right bottom corner to "CLICKED"
}
});
As explained in the commented section of the code, I simple want to update the TextView in the right bottom corner, writing in it the text "CLICKED".
The View parameter to AdapterView.OnItemClickListener onItemClick() is the view that was clicked. In your case it will be the item root RelativeLayout. Call findViewById() on it or use the ViewHolder pattern to obtain a reference to the TextView you want to update and just update it.
Also note that when the views are recycled i.e. your adapter's getView() is called with a non-null convertView, you need to reset the TextView to its default state.
You may not need to set a TextView to "Clicked", if all you want to do is give the user the feedback that they have checked an item. An alternative might be to do the following. Note, this method will also help you set a textview to "clicked" if you still need to.
To check an item I would extend your RelativeLayout as follows:
public class CheckableRelativeLayout extends RelativeLayout implements Checkable {
private boolean mChecked;
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
public CheckableRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
public void toggle() {
setChecked(!mChecked);
}
public boolean isChecked() {
return mChecked;
}
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
}
}
}
Then you can call parent.setItemChecked(position,true); in onItemClick which will actually set the item as checked within the AdapterView.
Doing this will then allow you to set a background selector on the extended RelativeLayout and the items will perform selected, pressed, checked etc actions. However, you don't need to use a background selector.
There is more, you can alway see whether the view is checked with gridview.getCheckedItemPosition() which you may find useful if you want to actually set the textview to "Clicked".
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
parent.setItemChecked(position,true);
yourAdapter.ViewHolder vh = (yourAdapter.ViewHolder) v.getTag();
vh.textView.setText("Clicked");
}
});
In your adapter you can hold a reference to you extended relative layout in your static ViewHolder class and if checked (e.g. holder.extendedrelativeLayout.isChecked()) then make sure you set the textView to "Clicked".
try gridView.invalidateViews(); it automatically calls getView() method of the adapter and updates the view.
What is happening i have a listview on which i putting background color change on selection.As well as by default i am putting the first listview item selected as
public class OneWayFlightResult extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater=null;
public OneWayFlightResult(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.row, null);
TextView flightTime = (TextView)vi.findViewById(R.id.flightTime); // title
TextView flightCompanyName = (TextView)vi.findViewById(R.id.flightCompanyName); // title
TextView flightNumber = (TextView)vi.findViewById(R.id.flightNumber); // title
ImageView flightLogo = (ImageView)vi.findViewById(R.id.flightLogo);
HashMap<String, String> flight = new HashMap<String, String>();
flight = data.get(position);
flightTime.setText(flight.get(TestActivity.FlightTime));
flightCompanyName.setText(TestActivity.FlightCompanyName);
flightNumber.setText(TestActivity.FlightNumber);
if(position == 0){
vi.setBackgroundResource(R.drawable.selection_effect);
vi.setSelected(true);
}
return vi;
}
This is XML file i am using in this selection_effect.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<shape>
<solid android:color="#ffffff" />
</shape>
</item>
<item>
<shape>
<solid android:color="#00a7eb" />
</shape>
</item>
</selector>
So by default this the first list view is selected.Now when the user select the another listview item the first one remains selected and the other one also got the same effect.So how could change the effect on click of the listview item dynamically .Means by default first item comes up selected when the user selects other item other one get selected the effect from the default one get removed
I got solution for your problem. Do as following.
1) open your main layout file where ListView you have created.
Add android:choiceMode="singleChoice". This will look like below.
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:choiceMode="singleChoice" >
</ListView>
2) Open your list_item.xml layout file. In which, to your root view, add android:background="?android:attr/activatedBackgroundIndicator". In my sample project, its look like below.
<?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:background="?android:attr/activatedBackgroundIndicator"
android:orientation="vertical" >
//your views
</LinearLayout>
3) Open your activity file. After setting adapter to your ListView, add list.setSelector(R.drawable.selection_effect);. This will look like below.
ListView ls = (ListView) findViewById(R.id.listView1);
ListAdapter adapter = new ListAdapter(this, data);
ls.setAdapter(adapter);
ls.setSelector(R.drawable.selection_effect);
Here, selection_effect is drawable file which you have created in drawable directory.
I tested my code. Which is working fine.
4) To select first view by default, remove your code in BaseAdapter and put following code after completing 3rd step.
ls.setItemChecked(0,true);
You need to put it after above code like below.
ListAdapter adapter = new ListAdapter(data);
ls.setAdapter(adapter);
ls.setSelector(R.drawable.selection_effect);
ls.setItemChecked(0, true);
Explanation
ls.setSelector(R.drawable.selection_effect);
This will select row item based on selector you have defined in drawable directory.
ls.setItemChecked(0, true);
This will select first item by default at first time run. After you can select other items by clicking on them.
You could just declare an int for item clicked which defaults to the first item that starts clicked, then in onclick update accordingly.
int selected = <default>;
set in oncreate etc.
Then you can have onItemClicked listener and do this,
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (selected != i){
<listView>.getChildAt(selected).setBackgroundColor(getResources().getColor(android.R.color.background_dark));
<listView>.getChildAt(i).setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));
selected = i;
}
}
This will change the background colour of the previously selected item back to (in my case) the default android dark theme colour, set the newly selected one to a nice highlighted light blue, and update the selected int to reflect the newly selected item.
You can try like this:
after setting adapter for ListView set position to 0 for default selection i.e. listView.setSelection(0); and in onItemClick you get selected position (3rd parameter) of item, so inside onItemClick write listView.setSelection("that 3rd param");
I have had similar problem with ListView all you do is when item is clicked call a method on adapter, adadpter.SetPosition(position) {mSelectedPsoiton = position; notifyDataSetChanged();}, and in your getView function check if the position is equal to selectedPosition, then set background accordingly this never fails, focus does not work as ur in touch mode always
//adapter class
public override View GetView(int position, View convertView, ViewGroup parent) { TextView view = null; int lookupPos = position; if (null == convertView) { view = new TextView(_context); view.SetTextSize(ComplexUnitType.Sp, 20); view.SetPadding(_pixels, _pixels, _pixels, _pixels); } else { view = convertView as TextView; }
if (position == mSelectedPos )
{
view.SetBackgroundResource(Android.Resource.Color.HoloBlueDark);
}
else
{
view.SetBackgroundResource(Resource.Drawable.listItemSelector);
}
return view;
}
public void SetSelectedPosition(int position) { mSelectedPos = position;
}
private int mSelectedPos = -1;
// ListView code, _adapter is adapter of listview
listView.SetOnItemClickListener (new OnItemClickListener() { #Override public void onItemClick(AdapterView adapter, View view, int pos, long id) { _adapter.SetSelectionPostion(pos); }
}
I have a listview and a button in my layout file. I'am adding items to listview on click of that button. The listview should be empty when the activity is started but it should grow by adding the items to it.
This is my code inside onCreate() :
list = (ListView)findViewById(R.id.inverterListView);
adapter = new ArrayAdapter<String>(InverterList.this, R.layout.inverters_list_row, R.id.inverterNumberTextViewInPanelListRow);
list.setAdapter(adapter);
And here iam adding the items to listview onclick of a button.
adapter.add(inverterNo);
adapter.notifyDataSetChanged();
This works fine. Can anyone guide me to delete custom listview item ? Thanks in advance.
If you know the position of the item you can do this:
Object item = adapter.getItem(position);
adapter.remove(item);
adapter.notifyDataSetChanged();
You may write your own adapter extends BaseAdapter and implement all you need methods.
It is example of my adapter:
public class PeopleUserAdapter extends BaseAdapter
{
private List<User> users;
private int viewResourceId;
private Context context;
public PeopleUserAdapter(Context context, int viewResourceId)
{
this.context = context;
this.viewResourceId = viewResourceId;
this.users = new ArrayList<User>();
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
UserItemHolder holder;
if (convertView == null)
{
convertView = LayoutInflater.from(context).inflate(viewResourceId, parent, false);
holder = new UserItemHolder(convertView);
}
else holder = (UserItemHolder) convertView.getTag();
User user = getItem(position);
holder.name.setText("#" + user.getLogin());
return convertView;
}
#Override
public int getCount()
{
return users.size();
}
#Override
public User getItem(int position)
{
return users.get(position);
}
#Override
public long getItemId(int position)
{
return getItem(position).hashCode();
}
public void clear()
{
users.clear();
}
public void addAll(Collection<User> users)
{
this.users.addAll(users);
notifyDataSetChanged();
}
public void replace(Collection<User> users)
{
clear();
addAll(users);
}
public static PeopleUserAdapter init(Context context)
{
return new PeopleUserAdapter(context, R.layout.item_user);
}
}
adapter.remove(item) .. and then call adapter.notifyDataSetChanged();
In case you are using a custom adapter (for a custom layout listview), you will want to do this:
When your Adapter is something like:
public class YourAdapterName extends ArrayAdapter<yourObject>
then the code for deleting the selected ListView Item will be:
ListView yourListView = (ListView) findViewById(R.id.listviewid);
YourAdapterName adapter;
adapter = (YourAdapterName) yourListView.getAdapter();
yourObject theitem = adapter.getItem(position);
adapter.remove(theitem);
adapte.notifyDataSetChanged();
This is assuming you are inside an event that gives you access to the current position inside the listview. like:
public boolean onItemLongClick(AdapterView<?> parent, View strings,int position, long id)
or
public void onItemClick(AdapterView<?> arg0, View v, int position, long id)
Otherwise you will need to obtain that position some other way, like storing it (onItemClick or onItemLongClick) in a textView with Visibility.GONE, and retrieve it when clicking the button (this is silly, you can use all kinds of storage options, like global variables, database and such).
Make sure you have overridden the remove method on your custom adapter
For example if this is your add method:
#Override
public void add(String[] object) {
scoreList.add(object);
super.add(object);
}
then your remove method would look something like this:
#Override
public void remove(String[] object) {
scoreList.remove(object);
super.remove(object);
}
call the below two lines::
adapter.remove(inverterNo);
adapter.notifyDataSetChanged();
where inverterNo is your item
It easy; you only to need is: add a method public in your personalize adapter some this:
public void remove(int position) {
itemsMovieModelFiltered.remove(position);
notifyDataSetChanged();
}
Remenber, this method you must add in your personalize adapter.
Then, call this method from other
adapte=new PersonalizeListAdapter(getActivity().getApplicationContext(),
movieModelList);
adapte.remove(position);