I'm developing chat application and i've already design dummy chat history.But i'm stuck at how to group messages according to it's date and when we scroll it down,date indicator stick at the top position just like whats app. can you just show me the way, how can i achieve that? I've attached some screenshot below to elaborate my question.
Put your header in your custom lisview adapter layout and check everytime your current message date and previous message date. If date is same then hide your header otherwise show your header. See below:
holder.tvDate.setText(chatMessage.getDate());
if (position > 0) {
if (chatMessages.get(position).getDate().equalsIgnoreCase(chatMessages.get(position - 1).getDate())) {
holder.header.setVisibility(View.GONE);
} else {
holder.header.setVisibility(View.VISIBLE);
}
} else {
holder.header.setVisibility(View.VISIBLE);
}
Simple. Just add a header view to your ListView
TextView textView = new TextView(context);
textView.setText("Hello. I'm a header view");
listView.addHeaderView(textView);
for more details- https://developer.android.com/reference/android/widget/ListView.html#addHeaderView(android.view.View)
Update:
By far the simplest way to do this is to embed the date header view in every item. Then, all you need to do in bindView is compare the previous row's date to this row's date, and hide the date if it's the same. Something like this:
String thisDate = cursor.getString(dateIndex);
String prevDate = null;
// get previous item's date, for comparison
if (cursor.getPosition() > 0 && cursor.moveToPrevious()) {
prevDate = cursor.getString(dateIndex);
cursor.moveToNext();
}
// enable section heading if it's the first one, or
// different from the previous one
if (prevDate == null || !prevDate.equals(thisDate)) {
dateSectionHeaderView.setVisibility(View.VISIBLE);
} else {
dateSectionHeaderView.setVisibility(View.GONE);
}
Related
I have RecyclerView where every list item has an ImageButton, thee image of which I define in the adapter's onBindViewHolder():
int myVote = getMyVote();
if (myVote != 0) {
Log.d("dbg", myVote + "");
holder.ratingButton.setImageResource(R.drawable.ic_star_grey600_36dp);
}
So ratingButton is a star in the right bottom corner of the list item layout. Its shape is filled with gray color (and accordingly, a log record is pushed) if the condition (myVote != 0) is satisfied.
The problem is that when I scroll the list down I can watch other stars became filled even though I can see the only one record in the log window (for the correct list item). Moreover, this list items with incorrectly changed buttons repeat every 5 rows, and that's what's confusing me. If I changemListView.setItemViewCacheSize(0); the repeat period changes to 3, so we can assume it somehow connected with the RecyclerView's caching and recycling mechanism.
Please, help me to work the problem out. Thanks!
Don't forget to implement
public long getItemId(int position) {}
otherwise, you'll see repeated items in RecyclerView.
Try to change your code to:
if (myVote != 0) {
Log.d("dbg", myVote + "");
holder.ratingButton.setImageResource(R.drawable.ic_star_grey600_36dp);
} else {
holder.ratingButton.setImageResource(int another resource);
}
}
You may also have to write else part of main condition with some another resource like:
if (myVote != 0) {
Log.d("dbg", myVote + "");
holder.ratingButton.setImageResource(R.drawable.ic_star_grey600_36dp);
} else {
holder.ratingButton.setImageResource(int another_resource);
}
It is worked for me.
Im trying to load custom callLogs in a listView based on date as section header.In ListAdapter i compare each date with the previous date and set SectionHeaderLayout Visible/Invisible. When the ListView has been loaded the section header are displayed correctly but when i scroll the section headers are set Visible to wrong ListItems.
Please help me to figure out a solution.
This is how im trying to set SectionHeader through the adapter.
if (position == 0) {
checkDate = mDateStr;
holder.sectionHeaderDate.setVisibility(View.VISIBLE);
holder.sectionHeaderText.setText(mDateStr);
}
} else if (checkDate == null || !checkDate.equals(mDateStr)) {
checkDate = mDateStr;
holder.sectionHeaderDate.setVisibility(View.VISIBLE);
holder.sectionHeaderText.setText(mDateStr);
} else {
holder.sectionHeaderDate.setVisibility(View.GONE);
}
Thanks in Advance
I see this is old question, you have probably solved your problem, but I'll answer for others who will have the same problem.
If you want to show header based on previous date you can't do that by remembering last item that was passed to getView function.
The reason is scrolling, i.e. different direction when going up and down.
For example, if you have items
1,
2,
3,
4,
5
when you're going down, and current item is 3, previous was 2, and all will work.
But if you are going up, your previous item for 3 was actually 4, and that's where your problem happens.
so instead of keeping item, you should use positions.
this would be the sketch of solution that you can call inside of your getView function:
private void showHeader(ViewHolder holder, Call item, int position) {
boolean shouldShowHeader = false;
if (position == 0
|| !DateHelper.isSameDay(item.getDateTime(),
items.get(position - 1).getDateTime()))
shouldShowHeader = true;
if (shouldShowHeader) {
holder.header.setVisibility(View.VISIBLE);
holder.date.setText(DateHelper.getSimpleDate(item.getDateTime()));
} else {
holder.header.setVisibility(View.GONE);
}
}
Ok im making app and it have 15 button's and 6 textview's.I want when I press first button to change value of first textview(value is "") to something (number one for example).But problem is when i press second button if first textview is already set to some value to set set second textview to second value.
If you need something else ask in comments (sorry for bad English)
here is what I was doing(this is under onclick)when i press second button
if(textview1.equals("1")){
textview2.setText("2");}
else if (textview1.equals("")){
textview1.setText("2");
}
It sounds like you wish to show last 6 buttons pressed.
Store all pressed buttons in a List (i.e. LinkedList) of size 6. Initially, it will be empty.
Then whenever any button is pressed do two things:
1) add it to the List and delete old elements if size exceeds six.
2) set button values from List.
Second step can be achieved like this:
// all TextViews should be in a list
private List<TextView> textViews;
// declare as field
private List<String> memoryQueue = new ArrayList<String>();
public void update() {
//set fields for the pressed buttons
for (int i=0; i<6 && i<memoryQueue.size(); i++) {
String text = memoryQueue.get(i);
textViews.get(i).setText(text);
}
// set empty fields
for (int i = memoryQueue.size(); i<6; i++) {
textViews.get(i).setText("");
}
}
This code snippet assumes that you store your TextViews in a List.
And Easiest way to keep track of last six button:
public void buttonPressed(Button button) {
//get text based on your button
String text = button.getText();
if (memoryQueue.contains(text)) {
return;
}
memoryQueue.add(text);
if (memoryQueue.size() > 6) {
memoryQueue.remove(0);
}
}
Since you're concerned with the text inside of your text view, you should be using the object's getText method:
if( textview1.getText().equals("1") ){ // Edited
textview2.setText("2");
} else if (textview1.getText().equals("")){ //Edited
textview1.setText("2");
}
At first, you have to get the String text from TextView using getText() method then you can compare that String with another String. Now, change your condition as follows...
if(textview1.getText().toString().equals("1")){
textview2.setText("2");}
else if (textview1.getText().toString().equals("")){
textview1.setText("2");
}
I have a spinner with a few values and I fill it from my webservice.
Filling the spinner
int i = 0;
var dropItems = new List<SpinItem2>();
DataRow[] result = myOPTvalues.Tables[0].Select("FieldValue=" + item.FieldValue);
foreach (DataRow row in result)
{
var optItem = new PrevzemSpin();
optItem.FieldValue = row["FieldValue"].ToString();
if (optItem.FieldValue.Equals(""))
optItem.FieldValue = null;
optItem.FieldTextValue = row["FieldTextValue"].ToString();
if (optItem.FieldTextValue.Equals(""))
optItem.FieldTextValue = null;
dropItems.Add(new SpinItem2(i, optItem.FieldValue.ToString(), optItem.FieldTextValue.ToString()));
}
i = 1;
foreach (DataRow row in myOPTvalues.Tables[0].Rows)
{
var optItem = new PrevzemSpin();
optItem.FieldValue = row["FieldValue"].ToString();
if (optItem.FieldValue.Equals(""))
optItem.FieldValue = null;
optItem.FieldTextValue = row["FieldTextValue"].ToString();
if (optItem.FieldTextValue.Equals(""))
optItem.FieldTextValue = null;
if (optItem.FieldValue != item.FieldValue)
{
dropItems.Add(new SpinItem2(i, optItem.FieldValue.ToString(), optItem.FieldTextValue.ToString()));
}
++i;
}
For some reason it acts like the item that was inserted first is "selected" on default and then triggers the ItemSelected event which I use to send the selected but I don't want that.
Since there's quite a number of these spinners on my screen it really slows down the activity plus it also sends the incorrect values to the field and since I use the ItemSelect to detect if everything went OK (let's say the service fell or the values themselves changed on server (someone added a new field on the server application) while the user is completing the form etc.)
Is there someway to tell the app not to trigger that on activity load but on actual user interaction?
I can't speak for Android specifically, but I have encountered this many times with Windows.
The solution I usually use is to simply add a boolean loading variable. Set it to true at the beginning of your initialisation and then clear it at the end.
In your event handlers like ItemSelected you can simply check if this is being triggered as the result of the initial load.
private void onItemSelected(....)
{
if(loading)
{
return; //Ignore as form is still loading
}
//Normal event handling logic goes here
....
}
Before I declared GetView:
int LastSpinnerSelectedPosition;
Inside my spinner definition:
LastSpinnerSelectedPosition = 0;
My spinner ItemSelected event:
var CurrentSelectedIndex = SpinnerValue.SelectedItemPosition;
if (CurrentSelectedIndex != LastSpinnerSelectedPosition)
{
// WHATEVER I WANTED TO DO ON ITEM SELECT ANYWAY
// Fix the LastSpinnerSelectedPosition ;)
LastSpinnerSelectedPosition = CurrentSelectedIndex;
}
Simple ;D
Just for clarification, the event fires when an item is selected. The semantics are obviously flawed, but technically the item IS selected when it initially loads since you can then immediately ask the spinner for which item is selected, so as the other answers say, just ignore the first time it is selected since it's guaranteed to be the loading select, and then proceed as normal after that.
I am changing row background color if the fetching data from database size is more than zero as gray otherwise not changing anything.For first item i am setting default folder and remaining as list names for these lists also setting background same like above.When I scroll the list all the bacground positions are changed..I know that positions are changing while scrolling.How to solve this one?
First position should be always Default List. I am giving code snippet for understanding purpose
if(position == 0)
{
holder.listName.setText("Default List");
int c = //getting database table size
if(c == 0 )
{
holder.rowLayout.setBackgroundColor(Color.GRAY);
}
}
else
{
list =//getting lists from database(different table)
if(list!=null)
{
holder.listName.setText(list.getListName());
}
if(list size==0)
{
holder.rowLayout.setBackgroundColor(Color.GRAY);
}
}
The ListItem recycled when you scroll the List that is why you are getting random background for ListItem. You have to change background of ListItem to it default color.
as follows..
if(list size==0)
holder.rowLayout.setBackgroundColor(Color.GRAY);
else
holder.rowLayout.setBackgroundColor(Color.BLACK);