I have an ListView with BaseAdapter now I just make some listener to item when I click on item I show some hidden view in item.
Every time I click on some item, I show the hidden view or hide them if views are visible. But the problem I face is that I want to hide the other visible item when the I show a new item.
Here I click on some item and its shows the message date and detail:
Now when I click on other items, I want to hide the first one and show the second, like this:
But here in my code when I click on other item its of course will not hide the previous view. How can I do this trick ?
Simply keep a reference to the last view that was clicked, let's call it mLastViewShown;
new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mLastViewShown != null)
hideDetails();
mLastViewShown = view;
showDetails();
}
};
Now you have a variable to hide the details from the last user click.
So you want to hide all item's additional field when you click on some other item. In addition to this you also want to toggle visibility of an item's additional view on click on same item.
Here is your main activity:
public class MainActivity extends AppCompatActivity {
private List<ListData> list=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//get the toolbar instance
handleListClick();
list.add(new ListData("George","Surgeon"));
list.add(new ListData("Nancy","Dentist"));
list.add(new ListData("Henry","Nurse"));
}
private void handleListClick() {
ListView listView=findViewById(R.id.listView);
final CustomBaseAdapter customBaseAdapter=new CustomBaseAdapter(this,list);
listView.setAdapter(customBaseAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
customBaseAdapter.setCurrentSelected(position);
customBaseAdapter.notifyDataSetChanged();
}
});
}
}
Here is your custom base adapter:
public class CustomBaseAdapter extends BaseAdapter {
private List<ListData> myList = new ArrayList<ListData>();
private LayoutInflater inflater;
private Context context;
private int previousSelected=-1;
public CustomBaseAdapter(Context context, List<ListData> myList) {
this.myList = myList;
this.context = context;
inflater = LayoutInflater.from(this.context);
}
public void setCurrentSelected(int currentSelected){
if(previousSelected==currentSelected)
previousSelected=-1;
else
previousSelected=currentSelected;
}
#Override
public int getCount() {
return myList.size();
}
#Override
public ListData getItem(int position) {
return myList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MyViewHolder mViewHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.row_item, parent, false);
mViewHolder = new MyViewHolder(convertView);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (MyViewHolder) convertView.getTag();
}
ListData currentListData = getItem(position);
mViewHolder.tvMain.setText(currentListData.getMainText());
if(previousSelected==position){
mViewHolder.tvAdditional.setVisibility(TextView.VISIBLE);
mViewHolder.tvAdditional.setText(currentListData.getAdditionalText());
}else{
mViewHolder.tvAdditional.setVisibility(TextView.GONE);
}
return convertView;
}
private class MyViewHolder {
TextView tvMain, tvAdditional;
public MyViewHolder(View item) {
tvMain = (TextView) item.findViewById(R.id.main_text);
tvAdditional = (TextView) item.findViewById(R.id.additional_text);
}
}
}
Here is your ListData:
public class ListData {
private String mainText;
private String additionalText;
public ListData(String mainText, String additionalText) {
this.mainText = mainText;
this.additionalText = additionalText;
}
public String getMainText() {
return mainText;
}
public void setMainText(String mainText) {
this.mainText = mainText;
}
public String getAdditionalText() {
return additionalText;
}
public void setAdditionalText(String additionalText) {
this.additionalText = additionalText;
}
}
Here is your row_item.xml layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/main_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/additional_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
Here is activity_main.xml layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.dexter.stackoverflow.MainActivity">
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Related
I want to create a listview that displays the same clickable icon several times. I tried many ways, including a custom adapter with layout inflater but failed... At this point my ListView displays numbers instead of the icon. Can you help me please? here is my code
public class UserSelectionActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
static ArrayList<Integer> arrayOfIcons = new ArrayList<Integer>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_selection);
arrayOfIcons.clear();
for (int i=0; i<3; i++) {arrayOfIcons.add(R.drawable.edit);}
ArrayAdapter<Integer> adapter2 = new ArrayAdapter<Integer>(this, android.R.layout.simple_list_item_1, arrayOfIcons);
ListView listView2 = (ListView) findViewById(R.id.usersListView2);
listView2.setAdapter(adapter2);
listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//TODO
}
});
}
}
I don't do anything in onResume method, that's why I didn't share it
And my xml file :
<?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="#+id/usersListView2"
android:layout_width="80dp"
android:layout_height="450dp"
android:layout_alignParentEnd="true"
android:paddingTop="4dip"
android:paddingBottom="3dip" />
</RelativeLayout>
Hy, I suggest you to create a custom adapter:
1) create your list_item:
In res -> layout create a new file named list_item.xml. It contains only one imageView inserted into a ConstraintLayout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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">
<ImageView
android:id="#+id/imageViewIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="#mipmap/ic_launcher" />
2) In your activity_main.xml you have to inser your listView:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="#+id/listViewIcon"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
3) Now you have to create a new class call, for example, IconAdapter, where you create your custom adapter:
public class IconAdapter extends BaseAdapter {
Context context;
List<Integer> iconIDList;
/**
*
* #param context = activity context
* #param iconIDList = list with icon's id
*/
public IconAdapter(Context context, List<Integer> iconIDList) {
this.context = context;
this.iconIDList = iconIDList;
}
#Override
public int getCount() {
//return the size of my list
return iconIDList.size();
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
//inflate my view
if (convertView == null) {
LayoutInflater inflater;
inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.list_item, null);
}
//istantiate my imageView
ImageView imageView = convertView.findViewById(R.id.imageViewIcon);
//set imageView's icon
imageView.setImageResource(iconIDList.get(i));
//return my view
return convertView;
}
}
4) Now in your MainActivity, put all together:D
public class MainActivity extends AppCompatActivity {
List<Integer> iconIDList;
IconAdapter iconAdapter;
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//istantiate my components
iconIDList = new ArrayList<>();
listView = findViewById(R.id.listViewIcon);
iconAdapter = new IconAdapter(this, iconIDList);
int myIcon = R.drawable.ic_launcher_background;
//populate the list with icon's id
for (int i = 0; i < 5; i++) {
iconIDList.add(myIcon);
}
//set my custom adapter to the listView
listView.setAdapter(iconAdapter);
//set clickListner to the elements of my listView
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
//i is the index of the clicked element
Toast.makeText(MainActivity.this, "Click on element n. " + i, Toast.LENGTH_SHORT).show();
}
});
}
}
I hope that can help you!!! Good job!! If you have a question, comment my answer!!
In your comment you ask me how to add one listener for the name (textView) clicked and one for the icon clicked.
1) modify your list_item.xml file. Now we can use:
a LinearLayout instead of ConstraintLayout;
a textView;
a ImageButton instead of ImageView.
<?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="wrap_content"
android:orientation="horizontal"
android:descendantFocusability="blocksDescendants" > <!--this is very important to detect click-->
<TextView
android:id="#+id/textViewIcon"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="left|center"
android:text="TextView"
android:textSize="24sp" />
<ImageButton
android:id="#+id/imageButtonIcon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_weight="1"
app:srcCompat="#mipmap/ic_launcher" />
</LinearLayout>
2) Is better if you create a class that contains your data. We can call this class IconData:
public class IconData {
int iconID;
String text;
//constructor
public IconData(int iconID, String text) {
this.iconID = iconID;
this.text = text;
}
//getter and setter
public int getIconID() {
return iconID;
}
public void setIconID(int iconID) {
this.iconID = iconID;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
3) Now we have to change our IconAdapter.
We'll add an Interface to detect clicks on the ImageButton;
We'll change the list's data type;
We'll instatiate the newest TextView and ImageButton:
//create custom adapter -> I extend my class using BaseAdapter
public class IconAdapter extends BaseAdapter {
//create an interface to comunicate the clicks on the imageButton
public interface MyIconAdapterInterface {
void setOnClickListnerMyImageButton (int position);
}
Context context;
//change the list's name and data type
List<IconData> iconIDTextList;
MyIconAdapterInterface myIconAdapterInterface;
/**
* #param context = activity context
* #param iconIDTextList = list with icon's id and text
* #param myIconAdapterInterface = the interface that mainActivity will implements
*/
public IconAdapter(Context context, List<IconData> iconIDTextList, MyIconAdapterInterface myIconAdapterInterface) {
this.context = context;
this.iconIDTextList = iconIDTextList;
this.myIconAdapterInterface = myIconAdapterInterface;
}
#Override
public int getCount() {
//return the size of my list
return iconIDTextList.size();
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(final int i, View convertView, ViewGroup viewGroup) {
//inflate my view
if (convertView == null) {
LayoutInflater inflater;
inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.list_item, null);
}
//istantiate my imageView and textView
ImageButton imageButton = convertView.findViewById(R.id.imageButtonIcon);
TextView textView = convertView.findViewById(R.id.textViewIcon);
//set imageView's button
int image = iconIDTextList.get(i).getIconID();
imageButton.setImageResource(image);
//set text
String text = iconIDTextList.get(i).getText();
textView.setText(text);
//setOnclickListner on my imageButton
imageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//pass the position of my clicks to the myIconAdapterInterface
myIconAdapterInterface.setOnClickListnerMyImageButton(i);
}
});
return convertView;
}
}
4) Finally we have to change the MainActivity.java's code:
implement our class with the new interface that we have create in our IconAdapter;
modify our list data type;
pass the newest list and the interface to the IconAdapter;
implement the interface's methods.
//I implement my MainActivity with IconAdapter.MyIconAdapterInterface. I create this interface
//in the iconAdapter class
public class MainActivity extends AppCompatActivity implements IconAdapter.MyIconAdapterInterface {
//change to iconIDTextList and change List data type
List<IconData> iconIDTextList;
IconAdapter iconAdapter;
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//istantiate my components
iconIDTextList = new ArrayList<>();
listView = findViewById(R.id.listViewIcon);
//the second "this" is refer to the IconAdapter.MyIconAdapterInterface
iconAdapter = new IconAdapter(this, iconIDTextList, this);
int myIcon = R.drawable.ic_launcher_background;
String myText = "Hello! ";
//populate the list with icon's id and text
for (int i = 0; i < 5; i++) {
iconIDTextList.add(new IconData(myIcon, myText + i));
}
//set my custom adapter to the listView
listView.setAdapter(iconAdapter);
//set clickListner to the elements of my listView
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
//i is the index of the clicked element
Toast.makeText(MainActivity.this, "Click on element n. " + i, Toast.LENGTH_SHORT).show();
}
});
}
//this is IconAdapter.MyIconAdapterInterface's method that I have to implement
#Override
public void setOnClickListnerMyImageButton(int position) {
//position = click's position
Toast.makeText(this, "Click on image n. "
+ position, Toast.LENGTH_SHORT).show();
}
}
Good Job!!
I have created a custom ListView, where the layout is definited in two XML, one which contain the definition of the ListView in a layout
For example activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/myListView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</RelativeLayout>
The other part of the XML is in another file, for example custom_list.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="wrap_content"
android:background="#drawable/list_row_selector">
<LinearLayout
android:id="#+id/photoList"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/takePhoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="#drawable/camera"/>
</LinearLayout>
</RelativeLayout>
In my activity i have declared actvivity_main.xml as main layout:
public class MainActivity extends AppCompatActivity{
private List<CustomRow> imageList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cmp_details);
/* Initialization structures, variable, ecc */
ListView lv = (ListView) findViewById(R.id.imageList);
adapter = new CustomList(this, imageList);
lv.setAdapter(adapter);
}
/* Add element list in ListView */
private void addList(int idC){
CustomRow cr = new CustomRow();
cr.setId(idC);
cr.setTitle("xxx "+ (idC+1));
cr.setThumbnailUrl(R.drawable.no_image);
imageList.add(cr);
adapter.notifyDataSetChanged();
}
private void takePhoto(){
//Do something
}
}
Custom List.java
public class CustomList extends BaseAdapter {
private Activity activity;
private LayoutInflater inflater;
private List<CustomRow> ListItem;
private ImageLoader imageLoader = AppController.getInstance().getImageLoader();
public CustomList(Activity activity, List<CustomRow> listPhotoItems) {
this.activity = activity;
this.ListItem = listPhotoItems;
}
#Override
public int getCount() {
return ListItem.size();
}
#Override
public Object getItem(int location) {
return ListItem.get(location);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null)
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null)
convertView = inflater.inflate(R.layout.custom_list, null);
if (imageLoader == null)
imageLoader = AppController.getInstance().getImageLoader();
ImageView thumbNail = (ImageView) convertView.findViewById(R.id.thumbnail);
TextView title = (TextView) convertView.findViewById(R.id.title);
CustomRow m = ListItem.get(position);
thumbNail.setImageResource(m.getThumbnailUrl());
title.setTag(m.getId());
title.setText(m.getTitle());
return convertView;
}
}
Now I have to implement the OnClickListener of takePhoto, how I can do this ?
How I can bind onClickListener from the activity ?
I tried this solution but not work...
you could use setonitemclicklistener
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
imageList.get(position); // here you will get the clicked item from
//your imagelist and you can check by getting a title by using this
String title= imageList.get(position).getTitle();
if(title.equals("you title to match")){
//do your action or you can get a particular position and click there
}
}
});
This is the final solution, I have solve my problem with this code:
lv.setAdapter(adapter);
lv.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
View convertView = v;
final ImageView photo = (ImageView) convertView.findViewById(R.id.takePhoto);
photo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(CmpDetails.this, "Click", Toast.LENGTH_SHORT).show();
}
});
return false;
}
});
tv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
list.get(position);
String str= list.get(position).getTitle();
if(str.equals("")){
//put your code here
}
}
});
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
TextView tv = (TextView) v.findViewById(R.id.textView1);
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do your code on click event
}
});
return super.getView(position, convertView, parent);
}
I have a recyclerview which has some cards inside it. Each card has a button and a listview inside it. I want listview to appear only when button is clicked. Initially I set onClickListener for button and onTouchListener for recyclerview but it didn't work for button. It only identified recyclerview listener, not button click listener. How can I set both listeners independently? Such that recyclerview touchlistener doesn't interfere in button click listener.
Secondly, I have two adapter here- one for listview and one for recyclerview. Listview adapter is called inside recyclerview adapter. If I call listview adapter when button is clicked, context is not found which I initially passed in recyclerview adapter.
This is recyclerview adapter:
public class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.ViewHolder>{
static Context activity;
ArrayList<ChatModel> chats = new ArrayList<ChatModel>();
boolean visible = false;
public ChatAdapter(Context a,ArrayList<ChatModel> _chats){
activity = a;
chats = _chats;
}
public static class ViewHolder extends RecyclerView.ViewHolder{
ImageButton expand;
ListView comments;
public ViewHolder(View v) {
super(v);
expand = (ImageButton)v.findViewById(R.id.chat_open);
comments = (ListView)v.findViewById(R.id.commentList);
}
}
#Override
public int getItemCount() {
// TODO Auto-generated method stub
if(chats.size()<=0)
return 0;
return chats.size();
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// TODO Auto-generated method stub
try{
holder.comments.setVisibility(View.GONE);
holder.expand.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("TAG","Expand clicked");
if (visible) {
visible = false;
holder.comments.setVisibility(View.GONE);
} else {
visible = true;
CommentsAdapter adap = new CommentsAdapter(activity, chats.get(position).getCommentList());
holder.comments.setAdapter(adap);
holder.comments.setVisibility(View.VISIBLE);
}
}
});
}catch(Exception e){
e.printStackTrace();
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
// TODO Auto-generated method stub
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.chat_item_card, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
}
This is listview adapter:
public class CommentsAdapter extends ArrayAdapter<CommentModel>{
public Context context;
ArrayList<CommentModel> data;
CommentModel detail;
public CommentsAdapter(Context a, ArrayList<CommentModel> d) {
super(a, R.layout.comment_item, d);
context = a;
data=d;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
detail = data.get(position);
View vi = inflater.inflate(R.layout.comment_item, parent, false);
TextView comment = (TextView) vi.findViewById(R.id.comment);
comment.setText(detail.getComment());
return vi;
}
}
This is cardview layout (row of recyclerview):
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_margin="5dp"
android:background="#e6e6e6"
card_view:cardCornerRadius="5dp"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#272626">
<ImageButton
android:layout_width="30dp"
android:layout_height="30dp"
android:background="#drawable/expand"
android:id="#+id/chat_open"
android:layout_marginRight="4dp"
android:padding="2dp"
android:clickable="true"/>
<ListView
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_below="#+id/chat_open"
android:layout_marginTop="5dp"
android:layout_alignLeft="#+id/chat_open"
android:layout_marginRight="4dp"
android:layout_marginBottom="3dp"
android:id="#+id/commentList">
</ListView>
</RelativeLayout>
</android.support.v7.widget.CardView>
I have a ListView which is inflated by a array of String. On top of the ListView I've added a button, and I want whenever user clicks on the button, the color of the 4 item changes automatically.
here is my Activity Code:
public class MainActivity extends Activity
{
String[] countryNames = {"Germany", "France", "Italy", "Spain", "Russia", "USA", "Iran", "China", "Inida"};
Button button;
ListView listView;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.listview);
button = (Button) findViewById(R.id.button_changeColor);
ListViewAdapter adapter = new ListViewAdapter(getApplicationContext());//
listView = (ListView) findViewById(R.id.listView_1);//
listView.setAdapter(adapter);//
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// here i want to change the the color 4th item.
}
});
}
private class ListViewAdapter extends BaseAdapter
{
LayoutInflater layoutInflater;
public ListViewAdapter(Context context)
{
layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount()
{
return countryNames.length;
}
#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)
{
ViewHolder viewHolder;
if (convertView == null)
{
convertView = layoutInflater.inflate(R.layout.listview_template, null);
viewHolder = new ViewHolder();
viewHolder.addedTextView = (TextView) convertView.findViewById(R.id.textView_Template);
convertView.setTag(viewHolder);
} else
{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.addedTextView.setText(countryNames[position]);
return convertView;
}
}
private class ViewHolder
{
TextView addedTextView;
}
}
And also here is my listview.xml File:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change Color"
android:id="#+id/button_changeColor"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="300dp"
android:id="#+id/listView_1">
</ListView>
</LinearLayout>
and finaly listview_template.xml:
<?xml version="1.0" encoding="utf-8"?>
<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:id="#+id/textView_Template"
/>
</LinearLayout>
So my question is, how to change a specific item's color by clicking on the button.
Like that?
listView.getChildAt( 4 );
View item_4 = listView.getChildAt(4);
item_4.setBackgroundResource( <new_background> );
( (TextView) item_4.findViewById( R.id.text1 ) ).setTextColor( <new_font_color> );
If you need to change all items, you can use cicle with iterator or simple For like this:
for(int i=0;i<listView.getChildCount();i++) {
View item = listView.getChildAt(i);
// some yours code
}
Since the Listview re-uses views when scrolled, you need to re-set the color in the adapter's getView method.
final ListViewAdapter adapter = new ListViewAdapter(getApplicationContext()) {
public boolean isHighlighted;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
super.getView(position, convertView, parent);
if (position == 4 && isHighlighted) {
convertView.setBackgroundColor(Color.RED);
}
return convertView;
}
}
And then have the button click listener, set the boolean:
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
adapter.isHighlighted = true;
}
});
In the same way you could also create a variable position inside the adapter and use it to highlight a specific item.
I've got a custom BaseAdapter and an add button in the main activity. The button opens a dialog with a textbox and you can add new elements to the list that way. The problem is that the list is not refreshing. In the onActivityResult() function I print the number of elements in the list and each time I hit OK in the dialog box the number increases, so I know it's just the refreshing that doesn't work. My BaseAdapter and my activity:
class ListaOrase extends BaseAdapter{
private Activity context;
ArrayList<String> orase;
public ListaOrase(Activity context){
this.context=context;
orase=new ArrayList<String>();
}
public void add(String string){
orase.add(string);
this.notifyDataSetChanged();
}
public View getView (int position, View convertView, ViewGroup list) {
View element;
if (convertView == null)
{
LayoutInflater inflater = context.getLayoutInflater();
element = inflater.inflate(R.layout.lista, null);
}
else element = convertView;
TextView elementLista=(TextView)element.findViewById(R.id.elementLista);
elementLista.setText(orase.get(position));
return element;
}
}
public class WeatherAppActivity extends ListActivity {
Button buton;
ListaOrase lista;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
lista=new ListaOrase(this);
buton=(Button)findViewById(R.id.buton);
lista.add("Bucuresti");
lista.add("Sibiu");
setListAdapter(lista);
}
public void add(View view){
Intent intent=new Intent();
intent.setClass(this, Adauga.class);
startActivityForResult(intent, 0);
}
public void onActivityResult (int requestCode, int responseCode, Intent data){
System.out.println("Apelata");
if(responseCode==1){
lista.add(data.getStringExtra("oras")); // e chiar getText()
System.out.println(lista.getCount());
lista.notifyDataSetChanged();
}
}
}
As you can see, I'm trying to refresh (notifyDataSetChanged();) both when adding a new element (in the BaseAdapter extending class) and in method onActivityResult, after the dialog passes the new element to the main Activity. I repeat, the element IS added to the list because the count increases, it just doesn't refresh.
Thanks for your answers!
It's normal that it doesn't refresh, you are adding an item to "lista" but the adapter keeps its own copy of that list, so or you set again the list in the adapter and then you call notifyDataChanged or you add the new item to the adapter.
Anyway I see couple of weird things, I thing you could semplify everything using an array adapter, you don't need to implement add,etc. I wrote some code simplyfing yours:
public class WeatherAppActivity extends ListActivity {
Button buton;
ItemsAdapter lista;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
List<String> initialList = new ArrayList<String>();
initialList.add("Bucuresti");
initialList.add("Sibiu");
lista=new ItemsAdapter(this, initialList);
buton=(Button)findViewById(R.id.button1);
buton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
lista.add(""+System.currentTimeMillis()); // e chiar getText()
lista.notifyDataSetChanged();
}
});
setListAdapter(lista);
}
class ItemsAdapter extends ArrayAdapter<String> {
public ItemsAdapter(Context context, List<String> list) {
super(context, R.layout.lista, list);
}
#Override
public View getView(final int position, View row, final ViewGroup parent) {
final String item = getItem(position);
ItemWrapper wrapper = null;
if (row == null) {
row = getLayoutInflater().inflate(R.layout.lista, parent, false);
wrapper = new ItemWrapper(row);
row.setTag(wrapper);
} else {
wrapper = (ItemWrapper) row.getTag();
}
wrapper.refreshData(item);
return row;
}
class ItemWrapper {
TextView text;
public ItemWrapper(View row) {
text = (TextView) row.findViewById(R.id.elementLista);
}
public void refreshData(String item) {
text.setText(item);
}
}
}
}
These are the xml that I have used:
main.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" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="63dp"
android:text="Button" />
<ListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" >
</ListView>
</RelativeLayout>
lista.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" >
<TextView
android:id="#+id/elementLista"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
This is the version of the adapter using a baseadapter:
class ItemsBaseAdapter extends BaseAdapter {
private List<String> items;
private Context mContext;
public ItemsBaseAdapter(Context context, List<String> list) {
items = list;
mContext = context;
}
public void addItem(String str) {
items.add(str);
}
#Override
public View getView(final int position, View row, final ViewGroup parent) {
final String item = (String) getItem(position);
ItemWrapper wrapper = null;
if (row == null) {
row = getLayoutInflater().inflate(R.layout.lista, parent, false);
wrapper = new ItemWrapper(row);
row.setTag(wrapper);
} else {
wrapper = (ItemWrapper) row.getTag();
}
wrapper.refreshData(item);
return row;
}
class ItemWrapper {
TextView text;
public ItemWrapper(View row) {
text = (TextView) row.findViewById(R.id.elementLista);
}
public void refreshData(String item) {
text.setText(item);
}
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
}
And this is the version of the list item wich also include an imageview on the left:
<?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="horizontal" >
<ImageView
android:layout_height="wrap_content"
android:src="#android:drawable/btn_star_big_on"
android:scaleType="fitCenter"
android:layout_width="wrap_content"
/>
<TextView
android:id="#+id/elementLista"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</LinearLayout>