I have a List view of ringtones with a play image view in each row for each ringtone.
This is the view of it.
Now obviously when a user clicks on a play button it should switch to pause button.
Now I have a problem :
I click on a play button and it will turn into pause button, but in the meantime when I click on a play button from another row it takes two clicks until the second one turns into the pause button.
This is my code :
Adapter
Product product = (Product) mDataItems.get(position);
holder.playPause=(ImageView)v.findViewById(R.id.playPause);
holder.playPause.setImageResource(product.getPlayPauseId());
holder.playPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (callback != null) {
callback.playPauseOnClick(position);
}
}
});
Activity
#Override
public void playPauseOnClick(int position) {
final Product product = productList.get(position);
if (paused) {
product.setPlayPauseId(R.drawable.ic_pause);
paused=false;
}else {
product.setPlayPauseId(R.drawable.ic_play);
paused = true;
}
adapter.notifyDataSetChanged();
};
I am already guessing the problem is in my condition
if(paused){
}
I would be grateful if you can offer me a better logic
you are using one pause field for all the rows so the first tap changes its status to true the second tap on the other row changes it to false and the sets the drawable
product.setPlayPauseId(R.drawable.ic_pause)
on the first row and the third tap works correctly.
you can define pause field for every product and inside if clause check the products pause filed
if(product.pause){
...
product.paused = false;
}else{
product.paused = true;
}
Here's a slimier case in this what i did is i stream audio ringtones from url in a RecyclerView .. make a class variable as
private int oldPosition = -1; , with this variable you'll keep track of which row is currently playing audio in RecyclerView
#Override
public void onRecyclerViewChildItemClick(BaseRecyclerViewHolder holder, int resourceId) {
super.onRecyclerViewChildItemClick(holder, resourceId);
switch (resourceId) {
case R.id.media_play_container:
int position = holder.getAdapterPosition();
if (oldPosition != -1)
resetResources();
if (oldPosition == position) {
resetResources();
oldPosition = -1;
return;
}
updateViewAtPosition(false, false); // update old selected view
oldPosition = position; // update position
BaseRecyclerViewAdapter adapter = (BaseRecyclerViewAdapter) getRecyclerView().getAdapter();
AudioItem item = (AudioItem) adapter.getItemAt(oldPosition);
String url = item.getAudioPreviewUrl();
// if url is valid show progress and play
if (AppUtils.ifNotNullEmpty(url)) {
updateViewAtPosition(true, false);
playRingtone(url);
}
break;
case R.id.iv_media_favorite:
break;
}
}
This method updates old row that is playing
updateViewAtPosition(false, false);
private void updateViewAtPosition(boolean isLoading, boolean isPlaying) {
RecyclerView recyclerView = getRecyclerView();
if (recyclerView == null || oldPosition == -1)
return;
BaseRecyclerViewAdapter adapter = (BaseRecyclerViewAdapter) recyclerView.getAdapter();
if (adapter == null)
return;
AudioItem item = (AudioItem) adapter.getItemAt(oldPosition);
item.setPlaying(isPlaying);
item.setLoading(isLoading);
adapter.update(oldPosition, item);
adapter.notifyItemChanged(oldPosition);
}
// reset media player
resetResources();
private void resetResources() {
resetMediaPlayer();
resetViewResources();
}
private void resetMediaPlayer() {
try {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.reset();
}
} catch (Exception e) {
Logger.caughtException(e);
}
}
private void resetViewResources() {
if (oldPosition == -1)
return;
updateViewAtPosition(false, false);
}
Related
I m using viewpager and its adapter i m displaying image and video as per condition.
I don't have fragment because i m using PagerAdapter.
Code:
pager.setOnPageChangeListener(pageChangeListener);
pager.post(new Runnable() {
#Override
public void run() {
pageChangeListener.onPageSelected(pager.getCurrentItem());
}
});
}
ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int arg0) {
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageSelected(int position) {
View view = mediaFullScreenImageAdapter.getActiveView(pager);
if (selectedPhotosByDate.get(position).getMessagetype().equalsIgnoreCase("VIDEO")) {
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
if (video_player.isPlaying()) {
Log.v("THISCALLEDD", "Y" + " : " + position);
video_player.pause();
}
}
}
};
#Nullable
public View getActiveView(final ViewPager viewPager) {
final PagerAdapter adapter = viewPager.getAdapter();
if (null == adapter || adapter.getCount() == 0 || viewPager.getChildCount() == 0) {
return null;
}
int position;
final int currentPosition = viewPager.getCurrentItem();
for (int i = 0; i < viewPager.getChildCount(); i++) {
final View child = viewPager.getChildAt(i);
final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams) child.getLayoutParams();
if (layoutParams.isDecor) {
continue;
}
final Field positionField;
try {
positionField = ViewPager.LayoutParams.class.getDeclaredField("position");
positionField.setAccessible(true);
position = positionField.getInt(layoutParams);
} catch (NoSuchFieldException e) {
break;
} catch (IllegalAccessException e) {
break;
}
if (position == currentPosition) {
return child;
}
}
return null;
}
Update:
selectedPhotosByDate = appDatabase.chatMessagesDao().getMediaByGroupId(topicid, "Y");
if (selectedPhotosByDate.size() > 0 && selectedPhotosByDate != null) {
mediaFullScreenImageAdapter = new MediaFullScreenImageAdapter(MediaFullScreenSlideActivity.this, selectedPhotosByDate);
pager.setAdapter(mediaFullScreenImageAdapter);
for (int i = 0; i < selectedPhotosByDate.size(); i++) {
if (messageid == selectedPhotosByDate.get(i).getMessageId()) {
position = i;
break;
}
}
pager.setCurrentItem(position);
pager.setOffscreenPageLimit(selectedPhotosByDate.size());
}
I am able to get logcat value . But my video doesn't get pause.
If my video is playing and user swipe for other item playing video must be paused.
Advanced help would be appreciated!
Based on the documentation here, onPageSelected is called when a new page is selected. That means, the active view that you are trying to get using the currentItem from the ViewPager will return you the current selected item rather than the previously selected item. So your reference to video_player is also wrong and hence it is not working.
A simple way to do this is to have a variable currentPosition. Update it in onPageSelected but before updating, get its view and pause the video. This way whenever you access it, you will first get the previous index and then you will update it to the current index for the next time.
As per my understanding ,you want to pause previous video when user swipe in viewpager .
#Override
public void onPageSelected(int position) {
View view = mediaFullScreenImageAdapter.getActiveView(pager);
if (selectedPhotosByDate.get(position).getMessagetype().equalsIgnoreCase("VIDEO")) {
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
if (video_player.isPlaying()) {
Log.v("THISCALLEDD", "Y" + " : " + position);
video_player.pause();
}
}
}
you are getting view object of current active position ,but you want to pause video of (position - 1 ),you need to have view object of previous position .
Finally resolved the issue.
I moved this code
View view = mediaFullScreenImageAdapter.getActiveView(pager);
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
video_player.pause();
to onPageScrolled() method instead of onPageSelected() method.
This worked for me with a Youtube video playing as an embedded iFrame in a WebView:
viewPager.addOnPageChangeListener(object : SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
// NOTE: this workaround pauses any playing Youtube video in the WebView, if the video screen is being switched out.
// This works by getting the ViewPager#focusedChild, which will be the WebView if that screen is currently in focus,
// before the next selected ViewPager screen gets switched-to/loaded.
viewPager.focusedChild?.findViewById<WebView>(R.id.video_view)?.onPause()
// NOTE: we do a postDelay below, to ensure the WebView gets put back into its resume state, if it being switched to.
// This is delayed, so that this happens after the ViewPager screen with the WebView, has time to load it into place.
postDelayed({ viewPager.focusedChild?.findViewById<WebView>(R.id.video_view)?.onResume() }, 200)
}
})
public class FragAdapter extends BaseAdapter implements View.OnClickListener {
WeakReference<Context> downloadsWeakReference;
List<DownloadRequest> downloadsPojos;
Button pause, resume, cancel, open, remove;
public FragAdapter(WeakReference<Context> downloadsWeakReference, List<DownloadRequest> downloadsPojos) {
this.downloadsWeakReference = downloadsWeakReference;
this.downloadsPojos = downloadsPojos;
}
#Override
public int getCount() {
if (downloadsPojos != null) {
return downloadsPojos.size();
} else {
return 0;
}
}
#Override
public Object getItem(int i) {
if (downloadsPojos != null) {
return downloadsPojos.get(i);
} else {
return null;
}
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
view = LayoutInflater.from(downloadsWeakReference.get()).inflate(R.layout.download_list_item, viewGroup, false);
}
ProgressBar progressBar = view.findViewById(R.id.downloadProgressBar);
TextView name = view.findViewById(R.id.name);
TextView down_progress = view.findViewById(R.id.down_progress);
TextView download_size = view.findViewById(R.id.download_size);
TextView status = view.findViewById(R.id.status);
cancel = view.findViewById(R.id.cancel);
pause = view.findViewById(R.id.pause);
resume = view.findViewById(R.id.resume);
open = view.findViewById(R.id.open);
remove = view.findViewById(R.id.remove);
pause.setTag(i);
resume.setTag(i);
remove.setTag(i);
cancel.setTag(i);
DownloadRequest downloadRequest = downloadsPojos.get(i);
progressBar.setMax((int) downloadRequest.getTotalBytes());
progressBar.setProgress((int) downloadRequest.getDownloadedBytes());
down_progress.setText(String.valueOf((int) downloadRequest.getDownloadedBytes() / 100));
name.setText(downloadRequest.getFileName());
download_size.setText(String.valueOf((int) downloadRequest.getTotalBytes() / 1000000));
//status.setText(String.valueOf(PRDownloader.getStatus(downloadsPojo.getDownloadId())));
cancel.setText(R.string.cancel);
pause.setText(R.string.pause);
resume.setText(R.string.resume);
pause.setOnClickListener(this);
resume.setOnClickListener(this);
cancel.setOnClickListener(this);
open.setOnClickListener(this);
remove.setOnClickListener(this);
return view;
}
public void updateResults(List<DownloadRequest> results) {
downloadsPojos = results;
notifyDataSetChanged();
}
public void hideView() {
cancel.setVisibility(View.GONE);
remove.setVisibility(View.VISIBLE);
pause.setVisibility(View.GONE);
resume.setVisibility(View.GONE);
open.setVisibility(View.VISIBLE);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.cancel:
int cancelTag = (int) view.getTag();
PRDownloader.cancel(Constant.downloadsPojoList.get(cancelTag).getDownloadId());
for (int i = 0; i < Constant.downloadsPojoList.size(); i++) {
if (Constant.downloadsPojoList.get(i).getDownloadId() == Constant.downloadsPojoList.get(cancelTag).getDownloadId()) {
Log.e("constant", "constant");
Constant.downloadsPojoList.remove(i);
}
}
updateResults(Constant.downloadsPojoList);
break;
case R.id.pause:
int pos = (int) view.getTag();
PRDownloader.pause(Constant.downloadsPojoList.get(pos).getDownloadId());
pause.setVisibility(View.GONE);
resume.setVisibility(View.VISIBLE);
break;
case R.id.resume:
int posi = (int) view.getTag();
PRDownloader.resume(Constant.downloadsPojoList.get(posi).getDownloadId());
Log.e("resume", String.valueOf(posi));
pause.setVisibility(View.VISIBLE);
resume.setVisibility(View.GONE);
break;
case R.id.open:
//For showing downloads folder.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + File.separator + "sachin")), "*/*");
downloadsWeakReference.get().startActivity(Intent.createChooser(intent, "Open Downloads using"));
break;
case R.id.remove:
int removeTag = (int) view.getTag();
for (int i = 0; i < Constant.downloadsPojoList.size(); i++) {
if (PRDownloader.getStatus(Constant.downloadsPojoList.get(i).getDownloadId()) == PRDownloader.getStatus(Constant.downloadsPojoList.get(removeTag).getDownloadId())) {
Constant.downloadsPojoList.remove(i);
Log.e("removed", "removed");
}
}
updateResults(Constant.downloadsPojoList);
break;
default:
}
}
}
In this list each list item has five button PAUSE, RESUME, CANCEL, OPEN, REMOVE. In which two buttons will show at a time and other button visibility will become gone.
This is an download list that shows which file is downloading with two buttons, CANCEL and PAUSE, after clicking PAUSE button, PAUSE visibility will become GONE and RESUME visibility will become VISIBLE, and after clicking RESUME button RESUME's visibility becomes GONE and PAUSE visibility becomes VISIBLE.
So, the problem is when I download two file and click the pause button of first item, the resume button will appear on the second item not on the first.And it forbid me to pause second downloading.
Introduce boolean variables in DownloadRequest model like isResume, isPause, etc.
After variables field applied in your model, try to change boolean true/false in conditions whenever you click on PAUSE, RESUME, etc button and make sure you do notifyDataSetChanged().
This will solve your issue.
If you still facing any issue then please provide model and activity code.
I have a list view of songs with play and pause button in every row..
I can't have two pause Icon(two playing song) in my list view So I need to first reset all of them to play Icon then set the selected view to pause Icon..
How can I do this ? Or can you offer a better solution for this ?
This is my code :
In model class ( Product ) :
public int currentPosition= -1;
in Adapter:
public interface PlayPauseClick {
void playPauseOnClick(int position);
}
private PlayPauseClick callback;
public void setPlayPauseClickListener(PlayPauseClick listener) {
this.callback = listener;
}
.
.
.
holder.playPauseHive.setImageResource(product.getPlayPauseId());
holder.playPauseHive.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (callback != null) {
callback.playPauseOnClick(position);
if (position == product.currentPosition) {
product.setPlayPauseId(R.drawable.ic_pause);
//set the image to pause icon
}else{
//set the image to play icon
product.setPlayPauseId(R.drawable.ic_play);
}
notifyDataSetChanged();
}
}
});
my Callback inside my Activity:
#Override
public void playPauseOnClick(int position) {
final Product product = songList.get(position);
if(product.currentPosition == position){
product.currentPosition = -1; //pause the currently playing item
}else{
product.currentPosition = position; //play the item
}
this.adapter.notifyDataSetChanged();
}
For my case I use a variable to store the current playing item position. Let say
int x = -1; //-1 can indicate nothing was currently playing
So in the playPauseOnClick() you can do something like this
#Override
public void playPauseOnClick(int position) {
if(x == position){
x = -1; //pause the currently playing item
}else{
x = position; //play the item
}
this.adapter.notifyDataSetChanged();
}
The reason i remove product.setPlayPauseId() is because you really don't need them. You just need to set the play or pause icon based on your x varible which I created earlier. Do Something like this in your getView()
Product product = songList.get(position);
if (position == x) {
//set the image to pause icon
}else{
//set the image to play icon
}
So once you call adapter.notifyDataSetChanged() your adapter will do all the work for you. Whenever the x variable having the value -1 none of the icon will be display the pause icon, this can also make sure only one position will showing the pause icon as well.
Hope it help you.
I have a List view of ringtones with a play image view in each row for each ringtone ..
This is the view of it..
Now obviously when user clicks on a play button it should switch into pause button.. I have implemented this and it's all good so far :
Interface(In adapter)
public interface PlayPauseClick {
void playPauseOnClick(int position);
}
private PlayPauseClick callback;
public void setPlayPauseClickListener(PlayPauseClick listener) {
this.callback = listener;
}
Adapter(In getView)
Product product = (Product) mDataItems.get(position);
holder.playPause=(ImageView)v.findViewById(R.id.playPause);
holder.playPause.setImageResource(product.getPlayPauseId());
holder.playPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (callback != null) {
callback.playPauseOnClick(position);
}
}
});
Activity
#Override
public void playPauseOnClick(int position) {
final Product product = productList.get(position);
if (product.paused) {
product.setPlayPauseId(R.drawable.ic_pause);
product.paused=false;
}else {
product.setPlayPauseId(R.drawable.ic_play);
product.paused = true;
}
adapter.notifyDataSetChanged();
};
Now I have a problem :
I don't know how to track the currently playing row,I mean if user wants to play a song from another row, first I have to change currently pause toggle to play, then play the new one.
Can you help me with this please !?
After some digging I found Two answers..
1: We can store the index of the current song which is played in the adapter.
So we just need to turn on pause when we click on an other button.
In Adapter :
int currentPosition = -1;
...
if (callback != null) {
callback.playPauseOnClick(position);
if (currentPosition == -1){
currentPosition = position;
} else if (currentPosition == position){
currentPosition = -1;
} else if (currentPosition != -1 && currentPosition != position){
callback.playPauseOnClick(currentPosition);
currentPosition = position;
}
}
2: Set resources for every listview data item
inside callback or anywhere can get listview data:
#Override
public void playPauseOnClick(int position) {
final Product product = productList.get(position);
if (product.paused) {
for(int i=0;i< productList.size();i++)
{
movieList.get(i).setPlayPauseId(R.drawable.ic_play);
movieList.get(i).paused = true;
}
product.setPlayPauseId(R.drawable.ic_pause);
product.paused=false;
}else {
product.setPlayPauseId(R.drawable.ic_play);
product.paused = true;
}
adapter.notifyDataSetChanged();
}
You can do this
first, declare a global variable
int lastposition=null;
then
#Override
public void playPauseOnClick(int position) {
final Product product = productList.get(position);
if(lastposition!=null)
{
Product previous = productList.get(lastposition);
previous.setPlayPauseId(R.drawable.ic_pause);
previous.paused=false;
lastposition=position;
} else lastposition=position;
if (product.paused) {
//new loadSingleView().execute(product.image_url);
//Log.d(LOG, product.image_url);
product.setPlayPauseId(R.drawable.ic_pause);
product.paused=false;
}else {
product.setPlayPauseId(R.drawable.ic_play);
product.paused = true;
}
adapter.notifyDataSetChanged();
};
Replace the above code with code in your activity
You could hold a variable "mCurrentPosition" to hold the currently playing track.
Then create two separate methods, one for play and one for pause. Simply pause the current track and play the one that was clicked.
Remember to also set the current position when you play a new track.
Something like this:
#Override
public void onClick(View v) {
if (callback != null) {
callback.pause(mCurrentPosition);
mCurrentPosition = position;
callback.play(position);
}
}
You may need to adjust it a bit as I don't know how you've setup your "callback" or where "position" is coming from. I'm assuming something like "getAdapterPosition()". But hopefully you can see how to do it by this example. If not please comment.
Edit in response to updated question:
For the interface do something like this:
public interface PlayPauseClick {
void pause(int position);
void play(int position);
}
Edit2:
#Override
void pause(int position) {
if(position != null) {
Product product = productList.get(position);
product.setPlayPauseId(R.drawable.ic_play);
product.paused = true;
adapter.notifyDataSetChanged();
}
}
#Override
void play(int position) {
// Homework exercise.
}
Hi i have recyclerView row item consists of a play Button(Which change to stop and Play as toggle) and a play seek bar and TextView.
The each row plays different audios .
When i click on play button of respective row i am able to stop the other row audio ..
Addressing to the problem ..
When i am playing a audio of a respective row, the button of earlier row has to stow a play symbol (in the sense it has to change the state ) please help me how to update the other rows of recyclerView when the other item is clicked
#Override
public void onBindViewHolder(final ViewHolder holder, final int i) {
if (holder.viewType == ROW_TYPE){
// holder.play_button.setImageResource(R.drawable.play_button);
if(i == selected_item){
}
else {
// holder.play_button.setImageResource();
}
JSONObject obj;
String mp3_url = null, caption = null, thumbnail_url = null;
try {
obj = voicesArray.getJSONObject(i);
mp3_url = obj.getString("mp3_url");
caption = obj.getString("caption");
thumbnail_url = obj.getString("thumbnail_url");
} catch (JSONException e) {
e.printStackTrace();
}
holder.list_text.setText(caption);
imageLoader.DisplayImage(thumbnail_url, holder.list_image);
final String finalMp3_url = mp3_url;
holder.play_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selected_item = i;
int ii = holder.getOldPosition();
// holder.play_button.setImageResource();
// updateItem(ii);
if(player != null){
player.reset();
holder.play_button.setImageResource(R.drawable.play_button);
myAudioPlay(holder, finalMp3_url);
}
else {
myAudioPlay(holder,finalMp3_url);
/*if (player == null) {
player = new MediaPlayer();
playAudiFile(finalMp3_url);
holder.play_button.setImageResource(R.drawable.pause_button);
} else if (player.isPlaying()) {
holder.play_button.setImageResource(R.drawable.play_button);
player.stop();
Log.d("player", "" + player);
player.reset();
} else {
holder.play_button.setImageResource(R.drawable.pause_button);
playAudiFile(finalMp3_url);
}*/
}
}
});
}
}
Apparently the purpose of a recyclerView is to recycle the views to minimize memory usage required for rendering view so setting an image in the view is not an apt solution,Their are many solutions for your problem the One i would pick(Pseudo code) is given below
Step 1. Create a Boolean value in your model class
bool isPlay=true;
Step 2. When you are playing an audio loop through your Model for the recycler adapter and set the value for isPlay accourdingly
for(object obj in listOfModels)
if(obj.Id!=idOfthePlayingView)
obj.isPlay=false;
Then notify your adapter
yourRecyclerAdapterObject.notifyDatasetChanged()