我有一个显示语音留言的ListView
(就像WhatsApp的一样),我正在使用BaseAdapter
,我的布局包含一个游戏button
和一个SeekBar
。
我想要的是点击播放button
播放音频,然后更新SeekBar
。
所以我实现了这个自我更新的自定义SeekBar
。
SelfUpdatingSeekBar.java
:
public class SelfUpdatingSeekBar extends SeekBar {
MediaPlayer mp;
boolean mActive;
public void setMediaPlayer(MediaPlayer mp){
this.mp = mp;
}
Runnable mUpdate = new Runnable() {
@Override
public void run() {
long totalDuration = mp.getDuration();
long currentDuration = mp.getCurrentPosition();
// Updating progress bar
int progress = (int)(getProgressPercentage(currentDuration, totalDuration));
setProgress(progress);
postDelayed(this, 100);
}
} ;
public void setActive(int progress) {
if (!mActive) {
mActive = true;
removeCallbacks(mUpdate);
setProgress(progress);
post(mUpdate);
}
}
public void setInactive(int progress) {
if (mActive) {
mActive = false;
removeCallbacks(mUpdate);
}
setProgress(progress);
}
public SelfUpdatingSeekBar(Context context) {
super(context);
}
public SelfUpdatingSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SelfUpdatingSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public SelfUpdatingSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public int getProgressPercentage(long currentDuration, long totalDuration){
Double percentage = (double) 0;
long currentSeconds = (int) (currentDuration / 1000);
long totalSeconds = (int) (totalDuration / 1000);
// calculating percentage
percentage =(((double)currentSeconds)/totalSeconds)*100;
// return percentage
return percentage.intValue();
}
}
这就是getView()
的样子:
public View getView(final int i, View convertView, ViewGroup viewGroup){
final ViewHolder viewHolder;
if(convertView == null){
LayoutInflater inflater = ((MainActivity) context).getLayoutInflater();
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.sent_voice_bubble, viewGroup, false);
viewHolder.sent_voice_seekbar = (SelfUpdatingSeekBar) convertView.findViewById(R.id.sent_seekbar);
viewHolder.sent_voice_seekbar.setMediaPlayer(mMediaPlayer);
viewHolder.sent_voice_play = (ImageView) convertView.findViewById(R.id.sent_playAudio);
viewHolder.sent_voice_container = convertView.findViewById(R.id.sent_vmessagesection);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(((int)(x * 0.7f)), RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
viewHolder.sent_voice_container.setLayoutParams(params);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.sent_voice_play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Check if the Item is currently playing
if(list.get(i).isPlaying()){
// Stop audio and save progress
stopItemAudio(list.get(i), viewHolder.sent_voice_seekbar);
// Change button's image to Pause ||
((ImageView) v).setImageDrawable(((MainActivity) context).pauseDrawable);
}else{
// Start audio and update the SeekBar
playItemAudio(list.get(i), viewHolder.sent_voice_seekbar);
// Change button's image to Play >
((ImageView) v).setImageDrawable(((MainActivity) context).playDrawable);
}
}
});
if(list.get(i).isPlaying()){
viewHolder.sent_voice_seekbar.setActive(list.get(i).seekbar_resume_position);
viewHolder.sent_voice_play.setImageDrawable(((MainActivity) context).pauseDrawable);
}else{
viewHolder.sent_voice_seekbar.setInactive(list.get(i).seekbar_resume_position);
viewHolder.sent_voice_play.setImageDrawable(((MainActivity) context).playDrawable);
}
return convertView;
}
public void stopItemAudio(AudioRow item, SelfUpdatingSeekBar seekBar){
if(mMediaPlayer == null){
mMediaPlayer = new MediaPlayer();
}
mMediaPlayer.stop();
item.setPlaying(false);
int percentage = getProgressPercentage(mMediaPlayer.getCurrentPosition(), mMediaPlayer.getDuration());
item.setSeekBarResumePosition(percentage);
item.setMediaPlayerResumePosition(mMediaPlayer.getCurrentPosition());
seekBar.setInactive(percentage);
notifyDataSetChanged();
}
public void playItemAudio(final AudioRow item, SelfUpdatingSeekBar seekBar){
if(mMediaPlayer == null){
mMediaPlayer = new MediaPlayer();
}
try {
mMediaPlayer.reset();
mMediaPlayer.setDataSource(item.audioPath);
mMediaPlayer.prepare();
mMediaPlayer.seekTo(item.mediaPlayer_resume_position);
seekBar.setActive(item.seekbar_resume_position); // Starts from where it stopped
mMediaPlayer.start();
// declaring Item started to play
item.setPlaying(true);
notifyDataSetChanged();
mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
item.setSeekBarResumePosition(0);
item.setPlaying(false);
}
});
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
public int getProgressPercentage(long currentDuration, long totalDuration){
Double percentage = (double) 0;
long currentSeconds = (int) (currentDuration / 1000);
long totalSeconds = (int) (totalDuration / 1000);
// calculating percentage
percentage =(((double)currentSeconds)/totalSeconds)*100;
// return percentage
return percentage.intValue();
}
}
问题是当我点击Item1
并开始播放时,点击Item2
SeekBars同时进行动画制作,这是预期的,因为我没有停止{{1}点击Item1
我的问题是:
Item2
时停止上一次播放Item1
的正确方法是什么?答案 0 :(得分:1)
您的SeekBar
实施不应该有自己的MediaPlayer
。您的活动中只有一个MediaPlayer
个实例。每次在列表视图中单击“播放”按钮时,您都会执行以下操作:
MediaPlayer mMediaPlayer = ((MainActivity) context).getSingleMediaPlayer();
((MainActivity) context).setCurrentlyPlayingItem(i);
mMediaPlayer.reset();
mMediaPlayer.setDataSource(item.audioPath);
mMediaPlayer.prepare();
notifyDatasetHasChanged()
现在,在您的getView()
实施中,如果第一个参数:i
不等于当前播放的MainActivity
项,则其SeekBar
应该为零。
MainActivity
也应该是实现更新runnable的那个。此时,您可能只想使用普通SeekBar
。要更新正确的视图,您需要首先确定它是否可见,因为用户可能已滚动到其他位置,因此您需要在MainActivity
中使用此功能:
public View getVisibleItemView(int position){
if(listview.getCount() > 0) {
int start = listview.getFirstVisiblePosition();
for (int i = start, j = listview.getLastVisiblePosition(); i <= j; i++) {
if (i == position) {
return listview.getChildAt(i - start);
}
}
}
return null;
}
此函数返回包含您要更新的SeekBar
的视图,但前提是它是可见的,否则返回null。在您的更新runnable中,您应该调用它,如果结果不为null,则更新SeekBar
。
此外,您可能需要考虑使用接口而不是在适配器中转换对MainActivity
的上下文引用。