編輯:關於Android編程
import java.io.File; import com.example.exmaudio.util.Utils; import android.app.Activity; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaRecorder.AudioEncoder; import android.media.MediaRecorder.AudioSource; import android.media.MediaRecorder.OnErrorListener; import android.media.MediaRecorder.OnInfoListener; import android.media.MediaRecorder; import android.media.MediaRecorder.OutputFormat; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.util.Log; import android.view.View.OnClickListener; import android.view.View; import android.view.Window; import android.widget.Button; import android.widget.TextView; public class MediaRecordActivity extends Activity implements OnClickListener, OnErrorListener, OnInfoListener { private static final String TAG = "MediaRecordActivity"; private TextView tv_record; private Button btn_start; private Button btn_stop; private MediaRecorder mMediaRecorder; private TextView tv_play; private Button btn_play; private Button btn_pause; private MediaPlayer mMediaPlayer; private int mPosition; private boolean bFirstPlay = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_media_record); tv_record = (TextView) findViewById(R.id.tv_record); btn_start = (Button) findViewById(R.id.btn_start); btn_stop = (Button) findViewById(R.id.btn_stop); tv_play = (TextView) this.findViewById(R.id.tv_play); btn_play = (Button) findViewById(R.id.btn_play); btn_pause = (Button) findViewById(R.id.btn_pause); btn_start.setOnClickListener(this); btn_stop.setOnClickListener(this); btn_play.setOnClickListener(this); btn_pause.setOnClickListener(this); btn_start.setEnabled(true); btn_stop.setEnabled(false); btn_play.setEnabled(false); btn_pause.setEnabled(false); initPlay(); } private void initPlay() { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { btn_play.setEnabled(true); btn_pause.setEnabled(false); bFirstPlay = true; mHandler.removeCallbacks(mPlayRun); mPlayTime = 0; } }); } private void preplay() { try { mMediaPlayer.reset(); //mMediaPlayer.setVolume(0.5f, 0.5f); //設置音量,可選 mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); String path = mRecordFile.getAbsolutePath(); mMediaPlayer.setDataSource(path); Log.d(TAG, "audio path = "+path); mMediaPlayer.prepare(); } catch (Exception e) { Log.d(TAG, "mMediaPlayer.prepare error: "+e.getMessage()); } mPlayTime = 0; } private void startPlay() { try { if (bFirstPlay == true) { preplay(); bFirstPlay = false; } mMediaPlayer.start(); } catch (Exception e) { Log.d(TAG, "mMediaPlayer.start error: " + e.getMessage()); } btn_play.setEnabled(false); btn_pause.setEnabled(true); mHandler.post(mPlayRun); } @Override protected void onPause() { // 先判斷是否正在播放 if (mMediaPlayer.isPlaying()) { // 如果正在播放我們就先保存這個播放位置 mPosition = mMediaPlayer.getCurrentPosition(); mMediaPlayer.stop(); mHandler.removeCallbacks(mPlayRun); } super.onPause(); } @Override protected void onResume() { if (mMediaPlayer!=null && mPosition>0) { mMediaPlayer.seekTo(mPosition); mMediaPlayer.start(); mHandler.post(mPlayRun); } super.onResume(); } private void startRecord() { createRecordDir(); mMediaRecorder = new MediaRecorder(); mMediaRecorder.reset(); mMediaRecorder.setOnErrorListener(this); mMediaRecorder.setOnInfoListener(this); mMediaRecorder.setAudioSource(AudioSource.MIC); //音頻源 mMediaRecorder.setOutputFormat(OutputFormat.AMR_NB); mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB); //音頻格式 //mMediaRecorder.setAudioSamplingRate(8); //音頻的采樣率。可選 //mMediaRecorder.setAudioChannels(2); //音頻的聲道數。可選 //mMediaRecorder.setAudioEncodingBitRate(1024); //音頻每秒錄制的字節數。可選 mMediaRecorder.setMaxDuration(10 * 1000); //設置錄制時長 //mMediaRecorder.setMaxFileSize(1024*1024*10); //setMaxFileSize與setMaxDuration設置其一即可 mMediaRecorder.setOutputFile(mRecordFile.getAbsolutePath()); try { mMediaRecorder.prepare(); mMediaRecorder.start(); } catch (Exception e) { Log.d(TAG, "mMediaRecorder.start error: " + e.getMessage()); } btn_start.setEnabled(false); btn_stop.setEnabled(true); mRecordTime = 0; mHandler.post(mRecordRun); } private File mRecordFile = null; private void createRecordDir() { File sampleDir = new File(Environment.getExternalStorageDirectory() + File.separator + "Download" + File.separator); if (!sampleDir.exists()) { sampleDir.mkdirs(); } File recordDir = sampleDir; try { mRecordFile = File.createTempFile(Utils.getNowDateTime(), ".amr", recordDir); Log.d(TAG, mRecordFile.getAbsolutePath()); } catch (Exception e) { Log.d(TAG, "createTempFile error: " + e.getMessage()); } } private void stopRecord() { if (mMediaRecorder != null) { mMediaRecorder.setOnErrorListener(null); mMediaRecorder.setPreviewDisplay(null); try { mMediaRecorder.stop(); } catch (Exception e) { Log.d(TAG, "mMediaRecorder.stop error: " + e.getMessage()); } mMediaRecorder.release(); mMediaRecorder = null; } btn_start.setEnabled(true); btn_stop.setEnabled(false); btn_play.setEnabled(true); mHandler.removeCallbacks(mRecordRun); } @Override public void onClick(View v) { int resid = v.getId(); if (resid == R.id.btn_start) { startRecord(); } else if (resid == R.id.btn_stop) { stopRecord(); } else if (resid == R.id.btn_play) { startPlay(); } else if (resid == R.id.btn_pause) { mMediaPlayer.pause(); btn_play.setEnabled(true); btn_pause.setEnabled(false); mHandler.removeCallbacks(mPlayRun); } } private Handler mHandler = new Handler(); private int mRecordTime = 0; private Runnable mRecordRun = new Runnable() { @Override public void run() { tv_record.setText(mRecordTime+"s"); mRecordTime++; mHandler.postDelayed(this, 1000); } }; private int mPlayTime = 0; private Runnable mPlayRun = new Runnable() { @Override public void run() { tv_play.setText(mPlayTime+"s"); mPlayTime++; mHandler.postDelayed(this, 1000); } }; @Override public void onError(MediaRecorder mr, int what, int extra) { if (mr != null) { mr.reset(); } } @Override public void onInfo(MediaRecorder mr, int what, int extra) { if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED || what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) { stopRecord(); } } }
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import com.example.exmaudio.util.Utils; import android.app.Activity; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioRecord.OnRecordPositionUpdateListener; import android.media.AudioTrack.OnPlaybackPositionUpdateListener; import android.media.AudioTrack; import android.media.MediaRecorder.AudioSource; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class AudioRecordActivity extends Activity implements OnClickListener { private static final String TAG = "AudioRecordActivity"; private TextView tv_record, tv_play; private Button btn_start, btn_stop, btn_play, btn_finish; private boolean isRecording, isPlaying; private Handler mHandler = new Handler(); private int mRecordTime, mPlayTime; private int frequence = 8000; private int channelConfig = AudioFormat.CHANNEL_IN_STEREO; //只能取值CHANNEL_OUT_STEREO //如果取值CHANNEL_OUT_DEFAULT,會報錯“getMinBufferSize(): Invalid channel configuration.” //如果取值CHANNEL_OUT_MONO,會報錯“java.lang.IllegalArgumentException: Unsupported channel configuration.” private int audioFormat = AudioFormat.ENCODING_PCM_16BIT; //AudioRecord只能錄制PCM格式 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_audio_record); tv_record = (TextView) findViewById(R.id.tv_record); btn_start = (Button) findViewById(R.id.btn_start); btn_stop = (Button) findViewById(R.id.btn_stop); tv_play = (TextView) findViewById(R.id.tv_play); btn_play = (Button) findViewById(R.id.btn_play); btn_finish = (Button) findViewById(R.id.btn_finish); btn_start.setEnabled(true); btn_stop.setEnabled(false); btn_play.setEnabled(false); btn_finish.setEnabled(false); btn_start.setOnClickListener(this); btn_stop.setOnClickListener(this); btn_play.setOnClickListener(this); btn_finish.setOnClickListener(this); createRecordDir(); } private File mRecordFile = null; private void createRecordDir() { File sampleDir = new File(Environment.getExternalStorageDirectory() + File.separator + "Download" + File.separator); if (!sampleDir.exists()) { sampleDir.mkdirs(); } File recordDir = sampleDir; try { mRecordFile = File.createTempFile(Utils.getNowDateTime(), ".pcm", recordDir); Log.d(TAG, mRecordFile.getAbsolutePath()); } catch (Exception e) { e.printStackTrace(); } } @Override public void onClick(View v) { int resid = v.getId(); if (resid == R.id.btn_start) { isRecording = true; new RecordTask().execute(); } else if (resid == R.id.btn_stop) { isRecording = false; } else if (resid == R.id.btn_play) { isPlaying = true; new PlayTask().execute(); } else if (resid == R.id.btn_finish) { isPlaying = false; } } private void refreshStatus(boolean isRecord, boolean isPlay) { if (isRecord || isPlay) { btn_start.setEnabled(false); btn_stop.setEnabled(isRecord?true:false); btn_play.setEnabled(false); btn_finish.setEnabled(isPlay?true:false); } else { btn_start.setEnabled(true); btn_stop.setEnabled(false); btn_play.setEnabled(true); btn_finish.setEnabled(false); } } private class RecordTask extends AsyncTask{ @Override protected Void doInBackground(Void... arg0) { try { // 開通輸出流到指定的文件 DataOutputStream dos = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(mRecordFile))); // 根據定義好的幾個配置,來獲取合適的緩沖大小 int bsize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioFormat); AudioRecord record = new AudioRecord(AudioSource.MIC, frequence, channelConfig, audioFormat, bsize); // 定義緩沖區 short[] buffer = new short[bsize]; //record.setNotificationMarkerPosition(1000); record.setPositionNotificationPeriod(1000); record.setRecordPositionUpdateListener(new RecordUpdateListener()); record.startRecording(); while (isRecording) { int bufferReadResult = record.read(buffer, 0, buffer.length); // 循環將buffer中的音頻數據寫入到OutputStream中 for (int i = 0; i < bufferReadResult; i++) { dos.writeShort(buffer[i]); } } record.stop(); dos.close(); Log.d(TAG, "mRecordFile.length()=" + mRecordFile.length()); } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onPreExecute() { refreshStatus(true, false); mRecordTime = 0; mHandler.postDelayed(mRecordRun, 1000); } @Override protected void onPostExecute(Void result) { refreshStatus(false, false); mHandler.removeCallbacks(mRecordRun); } } private Runnable mRecordRun = new Runnable() { @Override public void run() { mRecordTime++; mHandler.postDelayed(this, 1000); } }; private class RecordUpdateListener implements OnRecordPositionUpdateListener { @Override public void onMarkerReached(AudioRecord recorder) { } @Override public void onPeriodicNotification(AudioRecord recorder) { tv_record.setText(mRecordTime+"s"); } } private class PlayTask extends AsyncTask { @Override protected Void doInBackground(Void... arg0) { try { // 定義輸入流,將音頻寫入到AudioTrack類中,實現播放 DataInputStream dis = new DataInputStream( new BufferedInputStream(new FileInputStream(mRecordFile))); int bsize = AudioTrack.getMinBufferSize(frequence, channelConfig, audioFormat); short[] buffer = new short[bsize / 4]; AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, frequence, channelConfig, audioFormat, bsize, AudioTrack.MODE_STREAM); //track.setNotificationMarkerPosition(1000); track.setPositionNotificationPeriod(1000); track.setPlaybackPositionUpdateListener(new PlaybackUpdateListener()); track.play(); // 由於AudioTrack播放的是流,所以,我們需要一邊播放一邊讀取 while (isPlaying && dis.available() > 0) { int i = 0; while (dis.available() > 0 && i < buffer.length) { buffer[i] = dis.readShort(); i++; } // 然後將數據寫入到AudioTrack中 track.write(buffer, 0, buffer.length); } track.stop(); dis.close(); } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onPreExecute() { refreshStatus(false, true); mPlayTime = 0; mHandler.postDelayed(mPlayRun, 1000); } @Override protected void onPostExecute(Void result) { refreshStatus(false, false); mHandler.removeCallbacks(mPlayRun); } } private Runnable mPlayRun = new Runnable() { @Override public void run() { mPlayTime++; mHandler.postDelayed(this, 1000); } }; private class PlaybackUpdateListener implements OnPlaybackPositionUpdateListener { @Override public void onMarkerReached(AudioTrack track) { } @Override public void onPeriodicNotification(AudioTrack track) { tv_play.setText(mPlayTime+"s"); } } }
import java.util.HashMap; import android.app.Activity; import android.media.AudioManager; import android.media.SoundPool; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class SoundPlayActivity extends Activity implements OnClickListener { private SoundPool mSoundPool; private HashMapmSoundMap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sound_play); Button btn_play_all = (Button) findViewById(R.id.btn_play_all); Button btn_play_first = (Button) findViewById(R.id.btn_play_first); Button btn_play_second = (Button) findViewById(R.id.btn_play_second); Button btn_play_third = (Button) findViewById(R.id.btn_play_third); btn_play_all.setOnClickListener(this); btn_play_first.setOnClickListener(this); btn_play_second.setOnClickListener(this); btn_play_third.setOnClickListener(this); mSoundMap = new HashMap (); mSoundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 100); loadSound(1, R.raw.beep1); loadSound(2, R.raw.beep2); loadSound(3, R.raw.ring); } private void loadSound(int seq, int resid) { int soundID = mSoundPool.load(this, resid, 1); mSoundMap.put(seq, soundID); } private void playSound(int seq) { int soundID = mSoundMap.get(seq); mSoundPool.play(soundID, 1.0f, 1.0f, 1, 0, 1.0f); } @Override public void onClick(View v) { if (v.getId() == R.id.btn_play_all) { playSound(1); playSound(2); playSound(3); } else if (v.getId() == R.id.btn_play_first) { playSound(1); } else if (v.getId() == R.id.btn_play_second) { playSound(2); } else if (v.getId() == R.id.btn_play_third) { playSound(3); } } @Override protected void onDestroy() { if (mSoundPool != null) { mSoundPool.release(); } super.onDestroy(); } }
import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.FileInputStream; import java.util.ArrayList; import com.example.exmaudio.bean.LrcContent; import com.example.exmaudio.bean.MusicInfo; import com.example.exmaudio.util.LyricsLoader; import com.example.exmaudio.util.Utils; import com.example.exmaudio.widget.AudioController; import com.example.exmaudio.widget.AudioController.onSeekChangeListener; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.Activity; import android.graphics.Color; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.text.SpannableString; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.util.Log; import android.view.View; import android.view.animation.AnimationUtils; import android.widget.TextView; @TargetApi(Build.VERSION_CODES.KITKAT) public class MusicDetailActivity extends Activity implements AnimatorListener, onSeekChangeListener { private static final String TAG = "MusicDetailActivity"; private TextView tv_title; private TextView tv_artist; private TextView tv_music; private MusicInfo mMusic; private MediaPlayer mMediaPlayer; private AudioController ac_play; private LyricsLoader mLoader; private ArrayListmLrcList; private Handler mHandler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_music_detail); tv_title = (TextView) findViewById(R.id.tv_title); tv_artist = (TextView) findViewById(R.id.tv_artist); tv_music = (TextView) findViewById(R.id.tv_music); ac_play = (AudioController) findViewById(R.id.ac_play); ac_play.setonSeekChangeListener(this); mMusic = getIntent().getParcelableExtra("music"); tv_title.setText(mMusic.getTitle()); tv_artist.setText(mMusic.getArtist()); mLoader = LyricsLoader.getInstance(mMusic.getUrl()); mLrcList = mLoader.getLrcList(); mMediaPlayer = new MediaPlayer(); playMusic(mMusic.getUrl()); } private void playMusic(String file_path) { if (mMediaPlayer.isPlaying()) { mMediaPlayer.stop(); } if (Utils.getExtendName(file_path).equals("pcm")) { ac_play.setVisibility(View.GONE); PlayTask playTask = new PlayTask(); playTask.execute(file_path); } else { playMedia(file_path); } } private void playMedia(String filePath) { try { mMediaPlayer.reset(); //mMediaPlayer.setVolume(0.5f, 0.5f); //設置音量,可選 mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setDataSource(filePath); mMediaPlayer.prepare(); mMediaPlayer.start(); mHandler.post(mRefreshCtrl); mMediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { ac_play.setCurrentTime(0, 0); } }); ac_play.setMediaPlayer(mMediaPlayer); //以下處理歌詞 if (mLoader.getLrcList()!=null && mLrcList.size()>0) { mLrcStr = ""; for (int i=0; i seekto) { break; } } mCount = i; mPrePos = -1; mNextPos = 0; if (mCount > 0) { for (int j = 0; j < mCount; j++) { mNextPos = mLrcStr.indexOf(" \n",="" mprepos="" 1);="" mnextpos);="" startanimation(-mlineheight*i,="" onmusicpause()="" animtrany.pause();="" onmusicresume()="" animtrany.resume();="" mcount="0;" float="" mcurrentheight="0;" mlineheight="0;" mrefreshlrc="new" (mlineheight="=" 0)="" (tv_music.getheight()-tv_music.getpaddingtop())="" mlrclist.size()="" 2;="" "tv_music.getheight()="+tv_music.getHeight()); Log.d(TAG, " tv_music.getpaddingtop()="+tv_music.getPaddingTop()); Log.d(TAG, " ,mcurrentheight="+mCurrentHeight+" ,getheight="+tv_music.getHeight()); } }; private int mPrePos = -1, mNextPos = 0; private String mLrcStr; private ObjectAnimator animTranY; public void startAnimation(float aimHeight, int offset) { Log.d(TAG, " aimheight="+aimHeight); animTranY = ObjectAnimator.ofFloat(tv_music, " translationy",="" mcurrentheight,="" aimheight);="" animtrany.setduration(offset);="" animtrany.setrepeatcount(0);="" animtrany.addlistener(this);="" animtrany.start();="" onanimationstart(animator="" animation)="" onanimationend(animator="" (mcount="" 0?mNextPos:mLrcStr.length()-1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mCount++; tv_music.setText(spanText); if (mNextPos > 0 && mNextPos < mLrcStr.length()-1) { mPrePos = mLrcStr.indexOf("\n", mNextPos); mHandler.postDelayed(mRefreshLrc, 50); } } } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } private int frequence = 8000; private int channelConfig = AudioFormat.CHANNEL_IN_STEREO; //只能取值CHANNEL_OUT_STEREO private int audioFormat = AudioFormat.ENCODING_PCM_16BIT; private class PlayTask extends AsyncTask { @Override protected Void doInBackground(String... arg0) { try { // 定義輸入流,將音頻寫入到AudioTrack類中,實現播放 DataInputStream dis = new DataInputStream( new BufferedInputStream(new FileInputStream(arg0[0]))); int bsize = AudioTrack.getMinBufferSize(frequence, channelConfig, audioFormat); short[] buffer = new short[bsize / 4]; AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, frequence, channelConfig, audioFormat, bsize, AudioTrack.MODE_STREAM); track.play(); // 由於AudioTrack播放的是流,所以,我們需要一邊播放一邊讀取 while (dis.available() > 0) { int i = 0; while (dis.available() > 0 && i < buffer.length) { buffer[i] = dis.readShort(); i++; } // 然後將數據寫入到AudioTrack中 track.write(buffer, 0, buffer.length); } track.stop(); dis.close(); } catch (Exception e) { e.printStackTrace(); } return null; } } }
import com.example.exmaudio.R; import com.example.exmaudio.util.Utils; import android.content.Context; import android.graphics.Color; import android.media.MediaPlayer; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; public class AudioController extends RelativeLayout implements OnClickListener, OnSeekBarChangeListener { private static final String TAG = "AudioController"; private Context mContext; private ImageView mImagePlay; private TextView mCurrentTime; private TextView mTotalTime; private SeekBar mSeekBar; private int mBeginViewId = 0x7F24FFF0; private int dip_10, dip_40; private MediaPlayer mMediaPlayer; private int mCurrent = 0; private int mBuffer = 0; private int mDuration = 0; private boolean bPause = false; public AudioController(Context context) { this(context, null); } public AudioController(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; dip_10 = Utils.dip2px(mContext, 10); dip_40 = Utils.dip2px(mContext, 40); initView(); } private TextView newTextView(Context context, int id) { TextView tv = new TextView(context); tv.setId(id); tv.setGravity(Gravity.CENTER); tv.setTextColor(Color.WHITE); tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); params.addRule(RelativeLayout.CENTER_VERTICAL); tv.setLayoutParams(params); return tv; } private void initView() { mImagePlay = new ImageView(mContext); RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams(dip_40, dip_40); imageParams.addRule(RelativeLayout.CENTER_VERTICAL); mImagePlay.setLayoutParams(imageParams); mImagePlay.setId(mBeginViewId); mImagePlay.setOnClickListener(this); mCurrentTime = newTextView(mContext, mBeginViewId+1); RelativeLayout.LayoutParams currentParams = (LayoutParams) mCurrentTime.getLayoutParams(); currentParams.setMargins(dip_10, 0, 0, 0); currentParams.addRule(RelativeLayout.RIGHT_OF, mImagePlay.getId()); mCurrentTime.setLayoutParams(currentParams); mTotalTime = newTextView(mContext, mBeginViewId+2); RelativeLayout.LayoutParams totalParams = (LayoutParams) mTotalTime.getLayoutParams(); totalParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); mTotalTime.setLayoutParams(totalParams); mSeekBar = new SeekBar(mContext); RelativeLayout.LayoutParams seekParams = new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); totalParams.setMargins(dip_10, 0, dip_10, 0); seekParams.addRule(RelativeLayout.CENTER_IN_PARENT); seekParams.addRule(RelativeLayout.RIGHT_OF, mCurrentTime.getId()); seekParams.addRule(RelativeLayout.LEFT_OF, mTotalTime.getId()); mSeekBar.setLayoutParams(seekParams); mSeekBar.setMax(100); mSeekBar.setMinimumHeight(100); mSeekBar.setThumbOffset(0); mSeekBar.setId(mBeginViewId+3); mSeekBar.setOnSeekBarChangeListener(this); } private void reset() { if (mCurrent == 0 || bPause) { mImagePlay.setImageResource(R.drawable.audio_btn_down); } else { mImagePlay.setImageResource(R.drawable.audio_btn_on); } mCurrentTime.setText(Utils.formatTime(mCurrent)); mTotalTime.setText(Utils.formatTime(mDuration)); mSeekBar.setProgress((mCurrent==0)?0:(mCurrent*100/mDuration)); mSeekBar.setSecondaryProgress(mBuffer); } private void refresh() { invalidate(); requestLayout(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); removeAllViews(); reset(); addView(mImagePlay); addView(mCurrentTime); addView(mTotalTime); addView(mSeekBar); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { int time = progress * mDuration / 100; mMediaPlayer.seekTo(time); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { int time = seekBar.getProgress() * mDuration / 100; mSeekListener.onMusicSeek(mMediaPlayer.getCurrentPosition(), time); } private onSeekChangeListener mSeekListener; public static interface onSeekChangeListener { public void onMusicSeek(int current, int seekto); public void onMusicPause(); public void onMusicResume(); } public void setonSeekChangeListener(onSeekChangeListener listener) { mSeekListener = listener; } @Override public void onClick(View v) { if (v.getId() == mImagePlay.getId()) { if (mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); bPause = true; mSeekListener.onMusicPause(); } else { if (mCurrent == 0) { mSeekListener.onMusicSeek(0, 0); } mMediaPlayer.start(); bPause = false; mSeekListener.onMusicResume(); } } refresh(); } public void setMediaPlayer(MediaPlayer view) { mMediaPlayer = view; mDuration = mMediaPlayer.getDuration(); } public void setCurrentTime(int current_time, int buffer_time) { mCurrent = current_time; mBuffer = buffer_time; refresh(); } }
先上一下可以實現的效果圖 要實現的效果有幾方面 1、列不固定:可以根據數據源的不同生成不同的列數 2、表格內容可以根據數據源的定義合並列 3、要填寫的單元格可
有網友安裝了“天天酷跑專用修改(超哥破解)”、“妖艷制作”和“讓任何人都驚喜的東西”
這是在了解下拉刷新功能原理下的產物,下拉刷新可以說是國產APP裡面必有的功能,連Google都為此出了SwipeRefreshLayout,一種MD風格的下拉刷新。 不過
這兩天無意間看到一園友的博文實現Path2.0中絢麗的的旋轉菜單,感覺效果不錯,但是發現作者沒有處理線程安全的問題,所以在這裡我修正了下,並且改善下部分功能。今天發布這篇