How to change TextView text inside recyclerView items without notifyItemChanged? - android

I have a recyclerView which shows a title and link preview in every item. I want to search text in title and highlight searched_text if title contains the text.
Problem is: When I search something, everything works as expected but link preview start again and it takes few seconds to load preview again.
Is there any way to prevent reloading/restarting link preview? or
Is there any way to notify just a textView inside item and keep the other thing as it was?
Code for searching:
public boolean performSearch(TextView textViewResult,String searchKey){
this.searchKey = searchKey;
searchedPosition.clear();
for(int i=0;i<links.size();i++){
if(links.get(i).getTitle().toLowerCase().contains(searchKey)) {
searchedPosition.add(i);
}
}
if(searchedPosition.size()==0)
return false;//for downArrow
else {
currentPosition = 0;
for(int i=0;i<searchedPosition.size();i++)
notifyItemChanged(searchedPosition.get(i));
scrollListener.scrollToPosition(searchedPosition.get(currentPosition));
return true;
}
}
onBindViewholder:
#Override
public void onBindViewHolder(#NonNull final FileLayoutHolder2 holder, final int position) {
if(searchKey!=null && links.get(position).getTitle().toLowerCase().contains(searchKey)){
String newString = links.get(position).getTitle().replaceAll(
"(?i)"+ Pattern.quote(searchKey),
"<font color='red'>"+searchKey+"</font>");
holder.textViewHeading.setText(Html.fromHtml(newString));
}
else{
holder.textViewHeading.setText(links.get(position).getTitle());
}
try {//code for showing link preview: asynctask
}
catch(Exception ignored){}
}

Related

Android ListView Change Row Color On Value (not on Select)

Everything is working. i.e. Data is read from Firebase and displayed in the FirebaseListAdapter.
Here is the code in question
int urg = model.getUrgency();
if(urg == 1) v.setBackgroundColor(Color.RED);
Problem is it randomly colors more rows red than it should. i.e For my test I made only 1 record have urg = 1. Yet when I scroll, more than 1 rows turn red. How do I fix?
private void refreshListView(){
fbAdapter = new FirebaseListAdapter<Post>(this, Post.class,R.layout.post_message, query) {
#Override
protected void populateView(View v, Post model, int position) {
TextView messageText = (TextView)v.findViewById(R.id.message_text);
TextView messageTime = (TextView)v.findViewById(R.id.message_time);
messageText.setText(model.getMessageText());
messageTime.setText(shortTime.format(model.getPostTimeStamp()));
int urg = model.getUrgency();
if(urg == 1) v.setBackgroundColor(Color.RED);
}
};
mListView.setAdapter(fbAdapter);
mListView.requestFocus();
}
The reason for red color in more than one row is, there is no else block. Add an else block will fix this issue.
int urg = model.getUrgency();
if(urg == 1){
v.setBackgroundColor(Color.RED);
}else{
v.setBackgroundColor(Color.WHITE);
}

Get TextView line count in RecyclerView adapter?

I'm trying to count the number of lines of a TextView in a RecyclerView adapter.
Following answers from other questions (although not related to RecyclerViews), I tried adding this to my onBindViewHolder method:
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Message message = messages.get(position);
holder.textView.setText(message.getMessage());
holder.textView.setVisibility(View.VISIBLE);
// Get the number of lines
holder.textView.post(new Runnable() {
#Override
public void run() {
int lineCount = holder.textView.getLineCount();
Log.d("COUNT", String.valueOf(lineCount));
}
});
}
But when I open my app, the first RecyclerView item will initially show COUNT 0 (even though it has 5 lines). But when I scroll down a few items and then scroll back up to the first item, it will show the correct number of lines (COUNT 5).
So what am I doing wrong?
textView is reference to converted view in layout manager. When run() is executed, holder.textView maybe used in another item.
UPDATED
If you fast scroll, some views maybe won't be prepared. You can check that text in current view equals message.
Message message = messages.get(position);
holder.textView.setText(message.getMessage());
holder.textView.setVisibility(View.VISIBLE);
// Get the number of lines
holder.textView.post(new Runnable() {
#Override
public void run() {
if (holder.textView.getText().toString().equals(message.getMessage()) {
int lineCount = holder.textView.getLineCount();
Log.d("COUNT", String.valueOf(lineCount));
}
}
});

Reset icon of the last clicked view upon clicking a view in GridLayout

I am developing a music playing app but I've been stuck with fixing a bug for the last two days. Here is a screenshot of the app. Basically the user can add a new view, name it however he wishes and choose a mp3 file to link to that view.
As you can see Every view has a text that a little play icon. This icon switches to a pause icon while the audio is playing. Here you can see the pause icon.
Issue 1:
When the user starts a sound and then click on another square, the previous sound stops as it should and the new sound begins, but the old square's icon stays the pause icon, and so on the screen eventally many squares will have the pause icon while not actually playing sound.
Issue 2: Let's say that the user clicks the absolute first square, which in the arrayList corresponds to position 0. Then the user scrolls down to the point that the square he clicked is no longer visible. When the user scrolls up again the square he clicked on will have the play icon set, while playing sound. I figured that's because in my GridAdapter i set every newly recicled view to have the play icon and I can't figure out how to set an if statement. How should the adapter know wether the box is playing a sound?
Many thanks and love.
GridItemAdapter.java:
public class GridItemAdapter extends ArrayAdapter<GridItem> {
private static final String LOG_TAG = GridItemAdapter.class.getSimpleName();
public GridItemAdapter(Activity context, ArrayList<GridItem> gridItems) {
// Here, we initialize the ArrayAdapter's internal storage for the context and the list.
// the second argument is used when the ArrayAdapter is populating a single TextView.
// Because this is a custom adapter for two TextViews and an ImageView, the adapter is not
// going to use this second argument, so it can be any value. Here, we used 0.
super(context, 0, gridItems);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Check if the existing view is being reused, otherwise inflate the view
View gridItemView = convertView;
if(gridItemView == null) {
gridItemView = LayoutInflater.from(getContext()).inflate(
R.layout.grid_item, parent, false);
}
// Get the {#link AndroidFlavor} object located at this position in the list
GridItem currentGridItem = getItem(position);
// Find the TextView in the list_item.xml layout with the ID version_name
TextView nameTextView = (TextView) gridItemView.findViewById(R.id.text_1);
// set this text on the name TextView
nameTextView.setText(currentGridItem.getSoundName());
ImageView playIcon = (ImageView) gridItemView.findViewById(R.id.image_1);
playIcon.setImageResource(R.drawable.play_ic);
// Return the whole list item layout (containing 2 TextViews and an ImageView)
// so that it can be shown in the ListView
return gridItemView;
}
}
MainActivity.java snippets of interest :
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
/*
if (lastPosition != -1) {
Log.v(TAG3, "Inisde if block, lastposition = " + lastPosition);
// Whatever position you're looking for
int firstPosition = gridView.getFirstVisiblePosition();
int wantedChild = lastPosition - firstPosition;
View wantedView = gridView.getChildAt(wantedChild);
Log.v(TAG3, "lastRow initiated, lastrow = " + wantedView);
ImageView lastIc = (ImageView) wantedView.findViewById(R.id.image_1);
lastIc.setImageResource(R.drawable.play_ic);
}
*/
togglePlayback(i, view);
lastPosition = i;
Log.v(TAG3, "outside if block, lastPosition = " + lastPosition);
}
});
public void togglePlayback(int i, View v){
final View view = v;
if(!isPlaying) {
releaseMediaPlayer();
ImageView playIc = (ImageView) view.findViewById(R.id.image_1);
playIc.setImageResource(R.drawable.pause_ic);
GridItem word = gridItems.get(i);
try {
mMediaPlayer = MediaPlayer.create(MainActivity.this, Uri.parse(word.getSoundPath()));
}catch (IllegalArgumentException e){
e.printStackTrace();
}
mMediaPlayer.start();
isPlaying = true;
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
releaseMediaPlayer();
ImageView playIc = (ImageView) view.findViewById(R.id.image_1);
playIc.setImageResource(R.drawable.play_ic);
isPlaying = false;
}
});
}else{
releaseMediaPlayer();
ImageView playIc = (ImageView) view.findViewById(R.id.image_1);
playIc.setImageResource(R.drawable.play_ic);
isPlaying = false;
}
}
Here is a simple way to achieve it(I have not gone through your code since the snippet was not provided yet, the variables used below are self-explanatory):
First add a flag say isPlaying in the model class of an item in gridview
Now in getView method, add below code
if(itemList.get(index).isPlaying) {
//set the icon to pause one
} else {
//set the icon to playing one
}
Now, in view's click listener, add this
if(itemList.get(index).isPlaying) {
// write the code to pause the current song
} else {
// pause your <previousIndex> song
// play <index> item
itemList.get(index).isPlaying = true;
itemList.get(previousIndex).isPlaying = false;
previousIndex = index;
notifyDataSetChanged();
}
I have just written the basic logic, you need to write your code regarding playing/pause of your songs.
Hope this helps you.

Changing infoWindow view depending on click listener

I am trying to implement a Google Map marker with infoWindow that if someone clicks on this infoWindow, it plays a song and if clicks again, it stops. To visualize this, I write a custom infoWindow layout. There is, in infoWindow, you can see user and track info with a button. This button shows play icon if the track does not begin to play yet, and if it pressed (press on infoWindow, not the button), I hope it changes its icon from "play" to "stop". However, I cannot change my custom infoWindow's view depending on infoWindowClickListener activity. I tried to change infoWindowAdapter especially but I do not want to change view of all other infoWindows and also I want to see the change immediately. In this way, the infoWindow refreshes its view after I click on the marker again. In other words, it does not change the view simultaneously with my click action.
Here you can see what I am talking about. Stop status on left, play status on right:
Here is my futile effort for adapter:
public class OrangeInfoWindowAdapter implements GoogleMap.InfoWindowAdapter {
Context context;
ImageButton playButton;
boolean onPlay;
public OrangeInfoWindowAdapter(Context context, boolean onPlay) {
this.context = context;
this.onPlay = onPlay;
}
#Override
public View getInfoWindow(Marker arg0) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.orange_infowindow, null);
v.setMinimumWidth(280);
v.setMinimumHeight(120);
TextView tvUsername = (TextView) v.findViewById(R.id.tv_username);
TextView tvTrack = (TextView) v.findViewById(R.id.tv_track);
int index = arg0.getTitle().indexOf("*");
try {
tvUsername.setText(arg0.getTitle().substring(0, index - 1) + "\n" + arg0.getTitle().substring(index + 2));
} catch (StringIndexOutOfBoundsException e) {
}
tvUsername.setTextSize(10);
tvUsername.setTextColor(Color.rgb(70, 70, 70));
index = arg0.getSnippet().indexOf("*");
try {
tvTrack.setText(arg0.getSnippet().substring(0, index - 1) + "\n" + arg0.getSnippet().substring(index + 2));
} catch (StringIndexOutOfBoundsException e) {
}
tvTrack.setTextSize(10);
tvTrack.setTextColor(Color.rgb(230, 92, 1));
playButton = (ImageButton) v.findViewById(R.id.playButton);
if (onPlay)
onPlay();
return v;
}
public void onPlay() {
playButton.setBackgroundResource(R.drawable.info_stop_button);
}
public void onStop() {
playButton.setBackgroundResource(R.drawable.info_play_button);
}
#Override
public View getInfoContents(Marker arg0) {
return null;
}
}
And this is my onInfoWindowClick():
#Override
public void onInfoWindowClick(Marker marker) {
if (!infoWindowPlayerActive) {
int index = findMarkerIndex(marker);
OrangeInfoWindowAdapter infoWindowAdapter2 = new OrangeInfoWindowAdapter(getActivity().getApplicationContext(), true);
googleMap.setInfoWindowAdapter(infoWindowAdapter2);
new InfoWindowPlayerTask(mainActivity).execute(activities.get(index).getTrackId());
infoWindowPlayerActive = true;
}
else {
// same thing...
infoWindowPlayerActive = false;
}
}
If you want more information to understand the problem clearly, please ask me.
The GoogleMap API v.2 does not support any interaction on InfoWindow, besides opening and closing it.
However, there is an amazing hack implemented in this answer, on how you should create an interactive View inside your InfoWindow. Keep in mind that the same technique applies for Fragments too.
From the official documentation:
Note: The info window that is drawn is not a live view. The view is rendered as an image (using View.draw(Canvas)) at the time it is returned. This means that any subsequent changes to the view will not be reflected by the info window on the map. To update the info window later (e.g., after an image has loaded), call showInfoWindow(). Furthermore, the info window will not respect any of the interactivity typical for a normal view such as touch or gesture events. However you can listen to a generic click event on the whole info window as described in the section below.
I found a sloppy but working solution:
#Override
public void onInfoWindowClick(Marker marker) {
if (!infoWindowPlayerActive) {
googleMap.setInfoWindowAdapter(infoWindowAdapterOnPlay);
marker.showInfoWindow();
newClickedInfoWindowIndex = findMarkerIndex(marker);
if (lastClickedInfoWindowIndex != newClickedInfoWindowIndex) {
new InfoWindowPlayerTask(mainActivity).execute(activities.get(newClickedInfoWindowIndex).getTrackId());
}
else {
mainActivity.getPlayerManager().clickPlayPause();
}
lastClickedInfoWindowIndex = newClickedInfoWindowIndex;
infoWindowPlayerActive = true;
}
else {
googleMap.setInfoWindowAdapter(infoWindowAdapter);
marker.showInfoWindow();
mainActivity.getPlayerManager().clickPlayPause();
infoWindowPlayerActive = false;
}
}
public int findMarkerIndex(Marker marker) {
for (int i = 0; i < markers.size(); i++) {
if (marker.getPosition().equals(markers.get(i).getPosition())) {
return i;
}
}
return -1;
}
Of course, assume that infoWindowPlayerActive, lastClickedInfoWindowIndex, newClickedInfoWindowIndex are defined in the class above.

How to change background color of click view android using base Adapter

I want to set the background color of clicked TextView included in LinearLayout. But I am unable to set the respective background. I faced not
clear previous clicked background . if I clicked all then set all background color.
Would you suggest me ,
how to set clickable TextView included in LinearLayout background.
Here is my sample code:
holder.txtName = (TextView) convertView.findViewById(R.id.row_cell_text_dummy_multilevel);
holder.l_select = (LinearLayout) convertView.findViewById(R.id.linear_select);
holder.txtName.setTag(position);
holder.txtName.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
select_pos=(Integer) holder.txtName.getTag();
if (position==select_pos) {
holder.l_select.setTextColor(Color.RED);
}else {
holder.l_select.setTextColor(Color.WHITE);
}
}
});
I managed to get this much done, though you will have to do some homework and find out how to reflect the changes yourself. At the moment, the change gets reflected only when the view is scrolled.
But i hope it helps you.
1.declare a static variable that sets the position clicked on
private static int selectedPostion;
2.set the selectedPosition's value to -1 in the constructor
3.in the getView method in the onclickListener do this:
int value = (Integer)((TextView)v).getTag();
Log.e("tag","(TextView)v).getTag() : " + value);
Log.e("tag", "position : " + position);
if(value == position) {
selectedPostion = position;
}else {
selectedPostion = -1;
}
4.Under the onClick code entirely before return view write this:
if(selectedPostion == position) {
view.setBackgroundColor(mContext.getResources().getColor(R.color.even_color));
// or holder.l_select.setTextColor(Color.RED);
}else {
view.setBackgroundColor(mContext.getResources().getColor(android.R.color.white));
// or holder.l_select.setTextColor(Color.WHITE);
}
Hope it helps!

Categories

Resources