編輯:關於Android編程

滑動中...

滑動後

package com.iwanghang.drmplayer;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import com.iwanghang.drmplayer.utils.Contant;
/**
* Created by iwanghang on 16/4/26.
*/
public class DRMPlayerApp extends Application{
//SharedPreferences是Android平台上一個輕量級的存儲類,用來保存應用的一些常用配置
public static SharedPreferences sp;//SharedPreferences 直譯為 共享偏好
@Override
public void onCreate() {
super.onCreate();
//實例化,存儲名稱為SP_NAME,存儲模式為私有
sp = getSharedPreferences(Contant.SP_NAME, Context.MODE_PRIVATE);
//目的,比如在退出Activity時,保存循環模式,歌曲位置(第幾首歌曲)
//這裡,我在MainActivity的onDestroy時,調用SharedPreferences,保存進度值
}
}
/*
* Copyright (C) 2013 Andreas Stuetz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.iwanghang.drmplayer;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import com.astuetz.PagerSlidingTabStrip;
import com.astuetz.viewpager.extensions.sample.QuickContactFragment;
import com.iwanghang.drmplayer.utils.MediaUtils;
import com.iwanghang.drmplayer.vo.Mp3Info;
import java.nio.charset.CoderMalfunctionError;
import java.util.ArrayList;
public class MainActivity extends BaseActivity {
// private final Handler handler = new Handler();
private PagerSlidingTabStrip tabs;
private ViewPager pager;
private MyPagerAdapter adapter;
// private Drawable oldBackground = null;
// private int currentColor = 0xFFC74B46;
private MyMusicListFragment myMusicListFragment;
private NetMusicListFragment netMusicListFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
pager = (ViewPager) findViewById(R.id.pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
final int pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources()
.getDisplayMetrics());
pager.setPageMargin(pageMargin);
tabs.setViewPager(pager);
//修改主界面顏色,稍後修復功能,暫時使用默認顏色
//changeColor(currentColor);
//綁定服務
//服務在加載SplashActivity(歡迎頁面)的時候,已經啟動
//bindPlayService();
//這裡,我在MyMusicListFragment裡面綁定,而沒有在MainActivity裡綁定
}
@Override
public void publish(int progress) {
//更新進度條
}
@Override
public void change(int position) {
//更新歌曲位置.按鈕的狀態等信息
/**
* 本地音樂的播放UI實際上在MyMusicListFragment中,所以要
* 先在MyMusicListFragmen中,寫入public void changeUIStatus(int position){}
* 然後,傳參過去
*/
if (pager.getCurrentItem()==0){//如果頁面等於0,則說明選中的是第一個頁面,我的音樂頁面
myMusicListFragment.changeUIStatusOnPlay(position);
}else if (pager.getCurrentItem()==1){
}
}
// @Override
// public boolean onCreateOptionsMenu(Menu menu) {
// getMenuInflater().inflate(R.menu.main, menu);
// return true;
// }
//
// @Override
// public boolean onOptionsItemSelected(MenuItem item) {
//
// switch (item.getItemId()) {
//
// case R.id.action_contact:
// QuickContactFragment dialog = new QuickContactFragment();
// dialog.show(getSupportFragmentManager(), "QuickContactFragment");
// return true;
//
// }
//
// return super.onOptionsItemSelected(item);
// }
// private void changeColor(int newColor) {
//
// tabs.setIndicatorColor(newColor);
//
// // change ActionBar color just if an ActionBar is available
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
//
// Drawable colorDrawable = new ColorDrawable(newColor);
// Drawable bottomDrawable = getResources().getDrawable(R.drawable.actionbar_bottom);
// LayerDrawable ld = new LayerDrawable(new Drawable[] { colorDrawable, bottomDrawable });
//
// if (oldBackground == null) {
//
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
// ld.setCallback(drawableCallback);
// } else {
// getActionBar().setBackgroundDrawable(ld);
// }
//
// } else {
//
// TransitionDrawable td = new TransitionDrawable(new Drawable[] { oldBackground, ld });
//
// // workaround for broken ActionBarContainer drawable handling on
// // pre-API 17 builds
// // https://github.com/android/platform_frameworks_base/commit/a7cc06d82e45918c37429a59b14545c6a57db4e4
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
// td.setCallback(drawableCallback);
// } else {
// getActionBar().setBackgroundDrawable(td);
// }
//
// td.startTransition(200);
//
// }
//
// oldBackground = ld;
//
// // http://stackoverflow.com/questions/11002691/actionbar-setbackgrounddrawable-nulling-background-from-thread-handler
// getActionBar().setDisplayShowTitleEnabled(false);
// getActionBar().setDisplayShowTitleEnabled(true);
//
// }
//
// currentColor = newColor;
//
// }
// public void onColorClicked(View v) {
//
// int color = Color.parseColor(v.getTag().toString());
// changeColor(color);
//
// }
// @Override
// protected void onSaveInstanceState(Bundle outState) {
// super.onSaveInstanceState(outState);
// outState.putInt("currentColor", currentColor);
// }
// @Override
// protected void onRestoreInstanceState(Bundle savedInstanceState) {
// super.onRestoreInstanceState(savedInstanceState);
// currentColor = savedInstanceState.getInt("currentColor");
// changeColor(currentColor);
// }
// private Drawable.Callback drawableCallback = new Drawable.Callback() {
// @Override
// public void invalidateDrawable(Drawable who) {
// getActionBar().setBackgroundDrawable(who);
// }
//
// @Override
// public void scheduleDrawable(Drawable who, Runnable what, long when) {
// handler.postAtTime(what, when);
// }
//
// @Override
// public void unscheduleDrawable(Drawable who, Runnable what) {
// handler.removeCallbacks(what);
// }
// };
public class MyPagerAdapter extends FragmentPagerAdapter {
private final String[] TITLES = { "我的音樂", "網絡音樂"};
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
@Override
public int getCount() {
return TITLES.length;
}
@Override
public Fragment getItem(int position) {
//return SuperAwesomeCardFragment.newInstance(position);
if(position==0){
if(myMusicListFragment==null){
myMusicListFragment = MyMusicListFragment.newInstance();
}
return myMusicListFragment;
}else if (position == 1){
if(netMusicListFragment==null){
netMusicListFragment = netMusicListFragment.newInstance();
}
return netMusicListFragment;
}
return null;
//return MyMusicListFragment.newInstance();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//保存當前播放的一些狀態值
DRMPlayerApp app = (DRMPlayerApp) getApplication();
SharedPreferences.Editor editor = app.sp.edit();
//保存 當前正在播放的歌曲的位置
editor.putInt("currentPosition",playService.getCurrentPosition());
//保存 播放模式
editor.putInt("play_mode",playService.getPlay_mode());
//保存 提交
editor.commit();
//創建DRMPlayerApp繼承Application,同時需要在把AndroidManiFest中的public換成DRMPlayerApp
//在DRMPlayerApp的onCreate中 實例化 SharedPreferences
//在MainActivity的onDestroy中 保存狀態值
//在PlayService的onCreate中 恢復狀態值
}
}
package com.iwanghang.drmplayer; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.net.Uri; import android.os.Binder; import android.os.IBinder; import com.iwanghang.drmplayer.utils.MediaUtils; import com.iwanghang.drmplayer.vo.Mp3Info; import java.io.IOException; import java.util.ArrayList; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 音樂播放的服務組件 * 實現功能: * 播放 * 暫停 * 下一首 * 上一首 * 獲取當前歌曲的播放進度 * * 需要在AndroidManifest.xml添加以下代碼: ** * * 實現功能(播放模式play_mode): * 順序播放 * 隨機播放 * 單曲循環 */ public class PlayService extends Service implements OnCompletionListener,OnErrorListener{ private MediaPlayer mPlayer; private int currentPosition;//當前正在播放的歌曲的位置 ArrayListmp3Infos; private MusicUpdatrListener musicUpdatrListener; //創建一個單實力的線程,用於更新音樂信息 private ExecutorService es = Executors.newSingleThreadExecutor(); //播放模式 public static final int ORDER_PLAY = 1;//順序播放 public static final int RANDOM_PLAY = 2;//隨機播放 public static final int SINGLE_PLAY = 3;//單曲循環 private int play_mode = ORDER_PLAY;//播放模式,默認為順序播放 /** * @param play_mode * ORDER_PLAY = 1;//順序播放 * RANDOM_PLAY = 2;//隨機播放 * SINGLE_PLAY = 3;//單曲循環 */ //set方法 public void setPlay_mode(int play_mode) { this.play_mode = play_mode; } //get方法 public int getPlay_mode() { return play_mode; } private boolean isPause = false;//歌曲播放中的暫停狀態 public boolean isPause(){ return isPause; } public PlayService() { } public int getCurrentPosition(){ return currentPosition; } private Random random = new Random();//創建隨機對象 //MediaPlayer.Completion 播放完成 實現播放下一首功能 //播放完成以後,判斷播放模式(曲目循環方式) //為了實現循環後,可以顯示音樂信息,需要在PlayAcivity的change裡添加對應代碼 @Override public void onCompletion(MediaPlayer mp) { switch (play_mode){ case ORDER_PLAY://順序播放 next();//下一首 break; case RANDOM_PLAY://隨機播放 //currentPosition = random.nextInt(mp3Infos.size());//隨機下標為mp3Infos.size() //play(currentPosition); play(random.nextInt(mp3Infos.size())); break; case SINGLE_PLAY://單曲循環 play(currentPosition); break; default: break; } } //MediaPlayer.Error 播放錯誤 處理實現播放下一首功能出現的錯誤 @Override public boolean onError(MediaPlayer mp, int what, int extra) { mp.reset();//重啟 return false; } //內部類PlayBinder實現Binder,得到當前PlayService對象 class PlayBinder extends Binder{ public PlayService getPlayService(){ System.out.println("PlayService #1 " + PlayService.this); return PlayService.this; } } @Override public IBinder onBind(Intent intent) { return new PlayBinder();//通過PlayBinder拿到PlayService,給Activity調用 } @Override public void onCreate() { super.onCreate(); //恢復狀態值 DRMPlayerApp app = (DRMPlayerApp) getApplication(); currentPosition = app.sp.getInt("currentPosition",0); play_mode = app.sp.getInt("play_mode",PlayService.ORDER_PLAY); //創建DRMPlayerApp繼承Application,同時需要在把AndroidManiFest中的public換成DRMPlayerApp //在DRMPlayerApp的onCreate中 實例化 SharedPreferences //在MainActivity的onDestroy中 保存狀態值 //在PlayService的onCreate中 恢復狀態值 mPlayer = new MediaPlayer(); mPlayer.setOnCompletionListener(this);//注冊播放完成事件 mPlayer.setOnErrorListener(this);//注冊播放錯誤事件 mp3Infos = MediaUtils.getMp3Infos(this);//獲取Mp3列表 es.execute(updateSteatusRunnable);//更新進度值 } @Override public void onDestroy() { super.onDestroy(); //回收線程 if (es!=null && !es.isShutdown()){//當進度值等於空,並且,進度值沒有關閉 es.shutdown(); es = null; } } //利用Runnable來實現多線程 /** * Runnable * Java中實現多線程有兩種途徑:繼承Thread類或者實現Runnable接口. * Runnable接口非常簡單,就定義了一個方法run(),繼承Runnable並實現這個 * 方法就可以實現多線程了,但是這個run()方法不能自己調用,必須由系統來調用,否則就和別的方法沒有什麼區別了. * 好處:數據共享 */ Runnable updateSteatusRunnable = new Runnable() {//更新狀態 @Override public void run() { //不斷更新進度值 while (true){ //音樂更新監聽不為空,並且,媒體播放不為空,並且媒體播放為播放狀態 if(musicUpdatrListener!=null && mPlayer!=null && mPlayer.isPlaying()){ musicUpdatrListener.onPublish(getCurrentProgress());//獲取當前的進度值 } try { Thread.sleep(500);//500毫秒更新一次 } catch (InterruptedException e) { e.printStackTrace(); } } } }; //播放 public void play(int position){ if (position>=0 && position =mp3Infos.size()-1){//如果超出最大值,(因為第一首是0),說明已經是最後一首 currentPosition = 0;//回到第一首 }else { currentPosition++;//下一首 } play(currentPosition); } //上一首 previous public void prev(){ if (currentPosition-1<0){//如果上一首小於0,說明已經是第一首 currentPosition = mp3Infos.size()-1;//回到最後一首 }else { currentPosition--;//上一首 } play(currentPosition); } //默認開始播放的方法 public void start(){ if (mPlayer!=null && !mPlayer.isPlaying()){//判斷當前歌曲不等於空,並且沒有在播放的狀態 mPlayer.start(); } } //獲取當前是否為播放狀態,提供給MyMusicListFragment的播放暫停按鈕點擊事件判斷狀態時調用 public boolean isPlaying(){ if (mPlayer!=null){ return mPlayer.isPlaying(); } return false; } //獲取當前的進度值 public int getCurrentProgress(){ if(mPlayer!=null && mPlayer.isPlaying()){//mPlayer不為空,並且,為播放狀態 return mPlayer.getCurrentPosition(); } return 0; } //getDuration 獲取文件的持續時間 public int getDuration(){ return mPlayer.getDuration(); } //seekTo 尋找指定的時間位置 (跳到某個時間點進行播放) public void seekTo(int msec){ mPlayer.seekTo(msec); } //更新狀態的接口(PlayService的內部接口),並在BaseActivity中實現 public interface MusicUpdatrListener{//音樂更新監聽器 public void onPublish(int progress);//發表進度事件(更新進度條) public void onChange(int position); //更新歌曲位置.按鈕的狀態等信息 //聲明MusicUpdatrListener後,添加set方法 } //set方法 public void setMusicUpdatrListener(MusicUpdatrListener musicUpdatrListener) { this.musicUpdatrListener = musicUpdatrListener; } }
package com.iwanghang.drmplayer.custom;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;
import com.iwanghang.drmplayer.R;
/**
* Created by iwanghang on 16/4/26.
*/
public class FlingGalleryView extends ViewGroup {
private static final int SNAP_VELOCITY = 1000;
// 記錄當前屏幕下標,取值范圍是:0 到 getChildCount()-1
private int mCurrentScreen;
private Scroller mScroller;
// 速度追蹤器,主要是為了通過當前滑動速度判斷當前滑動是否為fling
private VelocityTracker mVelocityTracker;
// 記錄滑動時上次手指所處的位置
private float mLastMotionX;
private float mLastMotionY;
// Touch狀態值 0:靜止 1:滑動
private final static int TOUCH_STATE_REST = 0;
private final static int TOUCH_STATE_SCROLLING = 1;
// 記錄當前touch事件狀態--滑動(TOUCH_STATE_SCROLLING)、靜止(TOUCH_STATE_REST 默認)
private int mTouchState = TOUCH_STATE_REST;
// 記錄touch事件中被認為是滑動事件前的最大可滑動距離
private int mTouchSlop;
// 手指拋動作的最大速度px/s 每秒多少像素
private int mMaximumVelocity;
// 滾動到指定屏幕的事件
private OnScrollToScreenListener mScrollToScreenListener;
// 自定義touch事件
private OnCustomTouchListener mCustomTouchListener;
//滾動到每個屏幕時是否都要觸發OnScrollToScreenListener事件
private boolean isEveryScreen=false;
public FlingGalleryView(Context context) {
super(context);
init();
mCurrentScreen = 0;
}
public FlingGalleryView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlingGalleryView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.FlingGalleryView, defStyle, 0);
mCurrentScreen = a.getInt(R.styleable.FlingGalleryView_defaultScreen, 0);
a.recycle();
init();
}
private void init() {
mScroller = new Scroller(getContext());
final ViewConfiguration configuration = ViewConfiguration
.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
}
// 保證在同一個屏幕執行一下切屏事件的一些參數
private int count = -1;
private int defaultScreen = -1;
// 當滾動條滑動時調用,startScroll()設置的是參數,實際滑動,在其裡執行,
@Override
public void computeScroll() {
// mScroller.computeScrollOffset計算當前新的位置,true表示還在滑動,仍需計算
if (mScroller.computeScrollOffset()) {
// 返回true,說明scroll還沒有停止
scrollTo(mScroller.getCurrX(), 0);
if(isEveryScreen)singleScrollToScreen();
postInvalidate();
}
}
// 保證在同一個屏幕執行一下切屏事件
private void singleScrollToScreen() {
final int screenWidth = getWidth();
int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;
if (whichScreen > (getChildCount() - 1)) {
return;
}
if (defaultScreen == -1) {
defaultScreen = whichScreen;
count = 1;
} else {
if (defaultScreen == whichScreen && count == 0) {
count = 1;
} else {
if (defaultScreen != whichScreen) {
defaultScreen = whichScreen;
count = 0;
}
}
}
if (count == 0) {
if (mScrollToScreenListener != null) {
mScrollToScreenListener.operation(whichScreen, getChildCount());
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException(
"Workspace can only be used in EXACTLY mode.");
}
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException(
"Workspace can only be used in EXACTLY mode.");
}
final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
scrollTo(mCurrentScreen * width, 0);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
int childLeft = 0;
// 橫向平鋪childView
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
child.setOnTouchListener(childTouchListener);
if (child.getVisibility() != View.GONE) {
final int childWidth = child.getMeasuredWidth();
child.layout(childLeft, 0, childLeft + childWidth,
child.getMeasuredHeight());
childLeft += childWidth;
}
}
}
// 設定childView的Touch事件返回true,這樣可以在parentView中截獲touch(即onInterceptTouchEvent)的move,up等事件
private OnTouchListener childTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return true;
}
};
// 在系統向該ViewGroup及其各個childView觸發onTouchEvent()之前對相關事件進行一次攔截
/*
* down事件首先會傳遞到onInterceptTouchEvent()方法
* 如果該ViewGroup的onInterceptTouchEvent()在接收到down事件處理完成之後return
* false,那麼後續的move,
* up等事件將繼續會先傳遞給該ViewGroup,之後才和down事件一樣傳遞給最終的目標view的onTouchEvent()處理。
* 如果該ViewGroup的onInterceptTouchEvent()在接收到down事件處理完成之後return
* true,那麼後續的move,
* up等事件將不再傳遞給onInterceptTouchEvent(),而是和down事件一樣傳遞給該ViewGroup的onTouchEvent
* ()處理,注意,目標view將接收不到任何事件。
* 如果最終需要處理事件的view的onTouchEvent()返回了false,那麼該事件將被傳遞至其上一層次的view的onTouchEvent
* ()處理。 如果最終需要處理事件的view
* 的onTouchEvent()返回了true,那麼後續事件將可以繼續傳遞給該view的onTouchEvent()處理。
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mCustomTouchListener != null) {
mCustomTouchListener.operation(ev);
}
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE)
&& (mTouchState != TOUCH_STATE_REST)) {
return true;
}
final float x = ev.getX();
final float y = ev.getY();
switch (action) {
case MotionEvent.ACTION_MOVE:
// 計算X方向移動的距離
final int xDiff = (int) Math.abs(x - mLastMotionX);
final int touchSlop = mTouchSlop;
if (xDiff > touchSlop) {
// 移動方向小於45度時即X方向可以移動
if (Math.abs(mLastMotionY - y) / Math.abs(mLastMotionX - x) < 1) {
mTouchState = TOUCH_STATE_SCROLLING;
}
}
break;
case MotionEvent.ACTION_DOWN:
mLastMotionX = x;
mLastMotionY = y;
mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
: TOUCH_STATE_SCROLLING;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mTouchState = TOUCH_STATE_REST;
break;
}
return mTouchState != TOUCH_STATE_REST;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
final int action = ev.getAction();
final float x = ev.getX();
switch (action) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
// 終止滾動條的滑動動畫
mScroller.abortAnimation();
}
mLastMotionX = x;
count = -1;
defaultScreen = -1;
break;
case MotionEvent.ACTION_MOVE:
if (mTouchState == TOUCH_STATE_SCROLLING) {
final float t_width = (getWidth() / 4f);
// 最後一個屏幕向左移動時,不能超過屏幕的4分之一
if (getScrollX() > ((getChildCount() - 1) * getWidth() + t_width)) {
break;
}
// 第一個屏幕向右移動時,不能超過屏幕的4分之一
if (getScrollX() < ((t_width) * -1)) {
break;
}
final int deltaX = (int) (mLastMotionX - x);
mLastMotionX = x;
scrollBy(deltaX, 0);
}
break;
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_SCROLLING) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);// 使用pix/s為單位
int velocityX = (int) velocityTracker.getXVelocity();
if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
// 向右移動
snapToScreen(mCurrentScreen - 1, false);
} else if (velocityX < -SNAP_VELOCITY
&& mCurrentScreen < getChildCount() - 1) {
// 向左移動
snapToScreen(mCurrentScreen + 1, false);
} else {
snapToDestination();
}
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
mTouchState = TOUCH_STATE_REST;
break;
case MotionEvent.ACTION_CANCEL:
mTouchState = TOUCH_STATE_REST;
}
return true;
}
// 計算應該去哪個屏
private void snapToDestination() {
final int screenWidth = getWidth();
// 如果超過屏幕的一半就算是下一個屏
final int whichScreen = (getScrollX() + (screenWidth / 2))/ screenWidth;
snapToScreen(whichScreen, false);
}
// 切換屏幕
private void snapToScreen(int whichScreen, boolean isJump) {
// 判斷下一個屏幕是否有效,並糾正
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
if (getScrollX() != (whichScreen * getWidth())) {
final int delta = whichScreen * getWidth() - getScrollX();
count = -1;
defaultScreen = -1;
// 開始滾動動畫
mScroller.startScroll(getScrollX(), 0, delta, 0,
Math.abs(delta) * 2);
final int t_mCurrentScreen = mCurrentScreen;
mCurrentScreen = whichScreen;
// 判斷是否在同一個屏幕,不在則執行切換屏幕
if (t_mCurrentScreen != whichScreen) {
// 防止重復執行切換屏幕事件
if (Math.abs(t_mCurrentScreen - whichScreen) == 1 && !isJump) {
doOnScrollToScreen();
}
}
invalidate();
}
}
private void doOnScrollToScreen() {
if (mScrollToScreenListener != null) {
mScrollToScreenListener.operation(mCurrentScreen, getChildCount());
}
}
/**
* 設置切換到的指定下標屏幕0至getChildCount()-1
* */
public void setToScreen(int whichScreen, boolean isAnimation) {
if (isAnimation) {
snapToScreen(whichScreen, true);
} else {
whichScreen = Math.max(0,
Math.min(whichScreen, getChildCount() - 1));
mCurrentScreen = whichScreen;
// 直接滾動到該位置
scrollTo(whichScreen * getWidth(), 0);
if (whichScreen != mCurrentScreen) {
doOnScrollToScreen();
}
invalidate();
}
}
/**
* 設置默認屏幕的下標
* */
public void setDefaultScreen(int defaultScreen) {
mCurrentScreen = defaultScreen;
}
/**
* 獲取當前屏幕的下標
* */
public int getCurrentScreen() {
return mCurrentScreen;
}
/**
* 注冊滾動到指定屏幕的事件
* */
public void setOnScrollToScreenListener(
OnScrollToScreenListener scrollToScreenListener) {
if (scrollToScreenListener != null) {
this.mScrollToScreenListener = scrollToScreenListener;
}
}
/**
* 注冊自定義Touch事件
* */
public void setOnCustomTouchListener(
OnCustomTouchListener customTouchListener) {
if (customTouchListener != null) {
this.mCustomTouchListener = customTouchListener;
}
}
/**
* 滾動到指定屏幕的事件(即切屏事件)
* */
public interface OnScrollToScreenListener {
public void operation(int currentScreen, int screenCount);
}
/**
* 自定義的一個Touch事件
* */
public interface OnCustomTouchListener {
public void operation(MotionEvent event);
}
/**
* 滾動到每個屏幕時是否都要觸發OnScrollToScreenListener事件
* */
public void setEveryScreen(boolean isEveryScreen) {
this.isEveryScreen = isEveryScreen;
}
}
Android中制作進度框和環形進度條的簡單實例分享
進度框import android.content.Context; import android.graphics.Canvas; import android.gra
Android ListView實現上拉加載更多和下拉刷新功能
本文實例為大家介紹了Android ListView下拉刷新功能的實現方法和功能,供大家參考,具體內容如下1、ListView優化方式界面緩存:ViewHolder+co
Android Developer:Memory Monitor演示
這個演示展示了在Android Studio中Memory Monitor工具基本的用法和流程。Memory Monitors實時報告了你的app分配的內存。它的優勢:在
學習Android從0開始之基礎篇(2)-AndroidMainfest.xml文件詳解
AndroidMainfest.xml文件詳解一、關於AndroidManifest.xmlAndroidManifest.xml 是每個android程序中必須的文件。