public class MainActivity extends Activity implements OnTouchListener {
//滚动显示和隐藏Menu,手指滑动需要达到的速度
public static final int SNAP_VELOCITY=200;
//屏幕宽度
private int screenWidth;
//menu最多可以滑动的左边缘
private int leftEdge;
//menu最多可以滑动的右边缘
private int rightEdge=0;
//menu完全显示时,留给content的宽度值
private int menuPadding=80;
//主内容布局
private View content;
//menu布局
private View menu;
//menu布局的参数,通过这个参数来更改leftMargin的值
private LinearLayout.LayoutParams menuParams;
//记录手指按下的横坐标
private float xDown;
//记录手指移动的横坐标
private float xMove;
//记录手指抬起的横坐标
private float xUp;
//menu当前是显示还是隐藏
private boolean isMenuVisible;
//用于计算手指滑动的速度
private VelocityTracker mVelocityTracker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
content.setOnTouchListener(this);
}
private void init(){
WindowManager wm=getWindowManager();
screenWidth=wm.getDefaultDisplay().getWidth();
content=findViewById(R.id.ll_content);
menu=findViewById(R.id.ll_menu);
menuParams=(LayoutParams) menu.getLayoutParams();
//将menu的宽度设置为屏幕宽度减去menuPadding
menuParams.width=screenWidth-menuPadding;
leftEdge=-menuParams.width;
menuParams.leftMargin=leftEdge;
//将content的宽度设置为屏幕宽度
content.getLayoutParams().width=screenWidth;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
createVelocityTracker(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
xDown=event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
xMove=event.getRawX();
int distanceX=(int)(xMove-xDown);// 移动的距离
if(isMenuVisible){//判断当前Menu是否已经显示,如果true,说明已经显示
menuParams.leftMargin=distanceX;
}
else{
menuParams.leftMargin=leftEdge+distanceX;
}
if(menuParams.leftMargin<leftEdge){
menuParams.leftMargin=leftEdge;
}
else if(menuParams.leftMargin>rightEdge){
menuParams.leftMargin=rightEdge;
}
menu.setLayoutParams(menuParams);
break;
case MotionEvent.ACTION_UP:
xUp=event.getRawX();
if(wantToShowMenu()){
if(shouldScrollToMenu()){
scrollToMenu();
}
else{
scrollToContent();
}
}
else if(wantToShowContent()){
if(shouldScrollToContent()){
scrollToContent();
}
else{
scrollToMenu();
}
}
recycleVelocityTracker();
break;
default:
break;
}
return true;
}
/**
* 判断当前手势的意图是不是想显示content。如果手指移动的距离是负数,且当前menu是可见的,则认为当前手势是想要显示content。
*
* @return 当前手势想显示content返回true,否则返回false。
*/
private boolean wantToShowContent() {
return xUp - xDown < 0 && isMenuVisible;
}
/**
* 判断当前手势的意图是不是想显示menu。如果手指移动的距离是正数,且当前menu是不可见的,则认为当前手势是想要显示menu。
*
* @return 当前手势想显示menu返回true,否则返回false。
*/
private boolean wantToShowMenu(){
return xUp-xDown>0&&!isMenuVisible;
}
/**
* 判断是否应该滚动将menu展示出来。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,
* 就认为应该滚动将menu展示出来。
*
* @return 如果应该滚动将menu展示出来返回true,否则返回false。
*/
private boolean shouldScrollToMenu(){
return xUp-xDown>screenWidth/2||getScrollVelocity()>SNAP_VELOCITY;
}
/**
* 判断是否应该滚动将content展示出来。如果手指移动距离加上menuPadding大于屏幕的1/2,
* 或者手指移动速度大于SNAP_VELOCITY, 就认为应该滚动将content展示出来。
*
* @return 如果应该滚动将content展示出来返回true,否则返回false。
*/
private boolean shouldScrollToContent(){
return xDown-xUp+menuPadding>screenWidth/2||getScrollVelocity()>SNAP_VELOCITY;
}
//将屏幕滚动到menu界面,滚动速度设为30
private void scrollToMenu(){
new ScrollTask().execute(30);
}
//将屏幕滚到到content界面,滚动速度为-30
private void scrollToContent(){
new ScrollTask().execute(-30);
}
//创建velocityTracker对象,并将触摸content界面的滑动事件加入velocityTracker当中
private void createVelocityTracker(MotionEvent event){
if(mVelocityTracker==null){
mVelocityTracker=VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}
//获取手指在Content界面滑动的速度
private int getScrollVelocity(){
mVelocityTracker.computeCurrentVelocity(1000);
int velocity=(int) mVelocityTracker.getXVelocity();
return Math.abs(velocity);
}
//回收VelocityTracker
private void recycleVelocityTracker(){
mVelocityTracker.recycle();
mVelocityTracker=null;
}
class ScrollTask extends AsyncTask<Integer, Integer, Integer>{
@Override
protected Integer doInBackground(Integer... speed) {
int leftMargin=menuParams.leftMargin;
//根据传入速度来滚动界面,当滚动达到左边界或右边界,跳出循环
while(true){
leftMargin=leftMargin+speed[0];
if(leftMargin>rightEdge){
leftMargin=rightEdge;
break;
}
if(leftMargin<leftEdge){
leftMargin=leftEdge;
break;
}
publishProgress(leftMargin);
sleep(10);
}
if(speed[0]>0){
isMenuVisible=true;
}
else{
isMenuVisible=false;
}
return leftMargin;
}
@Override
protected void onProgressUpdate(Integer... values) {
menuParams.leftMargin=values[0];
menu.setLayoutParams(menuParams);
}
@Override
protected void onPostExecute(Integer result) {
menuParams.leftMargin=result;
menu.setLayoutParams(menuParams);
}
private void sleep(long mills){
try {
Thread.sleep(mills);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}