本文实例为大家分享了Android实现上下菜单双向滑动的具体代码,供大家参考,具体内容如下
这是研究了网上大神双向左右滑动后实现的上下双向滑动特效,有兴趣的朋友可以看下面代码,注释很详细,原理就是根据手指滑动的方向,来将上下两个布局进行显示与隐藏。主要用了onTouch方法,获取滑动的距离进行偏移。
import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.RelativeLayout;
public class UpAndDownSlidinglayout extends RelativeLayout implements OnTouchListener{
public static final int SNAP_VELOCITY = 200;
public static final int DO_NOTHING = 0;
public static final int SHOW_UP_MENU = 1;
public static final int SHOW_DOWN_MENU = 2;
public static final int HIDE_UP_MENU = 3;
public static final int HIDE_DOWN_MENU = 4;
private int slideState;
private int screenWidth;
private int screenHeight;
private int touchSlop;
private float xDown;
private float yDown;
private float xMove;
private float yMove;
private float yUp;
private boolean isUpMenuVisible;
private boolean isDownMenuVisible;
private boolean isSliding;
private View upMenuLayout;
private View downMenuLayout;
private View contentLayout;
private View mBindView;
private MarginLayoutParams upMenuLayoutParams;
private MarginLayoutParams downMenuLayoutParams;
private RelativeLayout.LayoutParams contentLayoutParams;
private VelocityTracker mVelocityTracker;
public UpAndDownSlidinglayout(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
screenWidth = wm.getDefaultDisplay().getWidth();
screenHeight = wm.getDefaultDisplay().getHeight();
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
public void setScrollEvent(View bindView) {
mBindView = bindView;
mBindView.setonTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
createVelocityTracker(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 手指按下时,记录按下时的坐标
xDown = event.getRawX();
yDown = event.getRawY();
// 将滑动状态初始化为DO_NOTHING
slideState = DO_NOTHING;
break;
case MotionEvent.ACTION_MOVE:
xMove = event.getRawX();
yMove = event.getRawY();
int moveDistanceX = (int) (xMove - xDown);
int moveDistanceY = (int) (yMove - yDown);
// 检查当前的滑动状态
checkSlideState(moveDistanceX, moveDistanceY);
switch (slideState) {
case SHOW_UP_MENU:
contentLayoutParams.bottomMargin = -moveDistanceY;
checkUpMenuBorder();
contentLayout.setLayoutParams(contentLayoutParams);
break;
case HIDE_UP_MENU:
contentLayoutParams.bottomMargin = -upMenuLayoutParams.height - moveDistanceY;
checkUpMenuBorder();
contentLayout.setLayoutParams(contentLayoutParams);
case SHOW_DOWN_MENU:
contentLayoutParams.topMargin = moveDistanceY;
checkDownMenuBorder();
contentLayout.setLayoutParams(contentLayoutParams);
break;
case HIDE_DOWN_MENU:
contentLayoutParams.topMargin = -downMenuLayoutParams.height + moveDistanceY;
checkDownMenuBorder();
contentLayout.setLayoutParams(contentLayoutParams);
default:
break;
}
break;
case MotionEvent.ACTION_UP:
yUp = event.getRawY();
int upDistanceY = (int) (yUp - yDown);
if (isSliding) {
// 手指抬起时,进行判断当前手势的意图
switch (slideState) {
case SHOW_UP_MENU:
if (shouldScrollToUpMenu()) {
scrollToUpMenu();
} else {
scrollToContentFromUpMenu();
}
break;
case HIDE_UP_MENU:
if (shouldScrollToContentFromUpMenu()) {
scrollToContentFromUpMenu();
} else {
scrollToUpMenu();
}
break;
case SHOW_DOWN_MENU:
if (shouldScrollToDownMenu()) {
scrollToDownMenu();
} else {
scrollToContentFromDownMenu();
}
break;
case HIDE_DOWN_MENU:
if (shouldScrollToContentFromDownMenu()) {
scrollToContentFromDownMenu();
} else {
scrollToDownMenu();
}
break;
default:
break;
}
}else if (upDistanceY < touchSlop && isUpMenuVisible) {
// 当上侧菜单显示时,如果用户点击一下内容部分,则直接滚动到内容界面
scrollToContentFromUpMenu();
} else if (upDistanceY < touchSlop && isDownMenuVisible) {
// 当下侧菜单显示时,如果用户点击一下内容部分,则直接滚动到内容界面
scrollToContentFromDownMenu();
}
recycleVelocityTracker();
break;
}
return true;
}
private void createVelocityTracker(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}
private void checkSlideState(int moveDistanceX, int moveDistanceY) {
if(isUpMenuVisible){
if (!isSliding && Math.abs(moveDistanceY) >= touchSlop && moveDistanceY < 0) {
isSliding = true;
slideState = HIDE_UP_MENU;
}
}else if(isDownMenuVisible){
if (!isSliding && Math.abs(moveDistanceY) >= touchSlop && moveDistanceY > 0) {
isSliding = true;
slideState = HIDE_DOWN_MENU;
}
}else{
if (!isSliding && Math.abs(moveDistanceY) >= touchSlop && moveDistanceY > 0
&& Math.abs(moveDistanceX) < touchSlop) {
isSliding = true;
slideState = SHOW_UP_MENU;
contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
contentLayout.setLayoutParams(contentLayoutParams);
// 如果用户想要滑动上侧菜单,将上侧菜单显示,下侧菜单隐藏
upMenuLayout.setVisibility(View.VISIBLE);
downMenuLayout.setVisibility(View.GONE);
}else if(!isSliding && Math.abs(moveDistanceY) >= touchSlop && moveDistanceY < 0
&& Math.abs(moveDistanceX) < touchSlop){
isSliding = true;
slideState = SHOW_DOWN_MENU;
contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 0);
contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
contentLayout.setLayoutParams(contentLayoutParams);
// 如果用户想要滑动下侧菜单,将下侧菜单显示,上侧菜单隐藏
upMenuLayout.setVisibility(View.GONE);
downMenuLayout.setVisibility(View.VISIBLE);
}
}
}
private void checkUpMenuBorder() {
if (contentLayoutParams.bottomMargin > 0) {
contentLayoutParams.bottomMargin = 0;
} else if (contentLayoutParams.bottomMargin < -upMenuLayoutParams.height) {
contentLayoutParams.bottomMargin = -upMenuLayoutParams.height;
}
}
private void checkDownMenuBorder() {
if (contentLayoutParams.topMargin > 0) {
contentLayoutParams.topMargin = 0;
} else if (contentLayoutParams.topMargin < -downMenuLayoutParams.height) {
contentLayoutParams.topMargin = -downMenuLayoutParams.height;
}
}
private boolean shouldScrollToUpMenu() {
return yUp - yDown > upMenuLayoutParams.height / 2 || getScrollVelocity() > SNAP_VELOCITY;
}
private boolean shouldScrollToDownMenu() {
return yDown - yUp > downMenuLayoutParams.height / 2 || getScrollVelocity() > SNAP_VELOCITY;
}
private boolean shouldScrollToContentFromUpMenu() {
return yDown - yUp > upMenuLayoutParams.height / 2 || getScrollVelocity() > SNAP_VELOCITY;
}
private boolean shouldScrollToContentFromDownMenu() {
return yUp - yDown > downMenuLayoutParams.height / 2 || getScrollVelocity() > SNAP_VELOCITY;
}
private int getScrollVelocity() {
mVelocityTracker.computeCurrentVelocity(1000);
int velocity = (int) mVelocityTracker.getXVelocity();
return Math.abs(velocity);
}
class UpMenuScrollTask extends AsyncTask {
@Override
protected Integer doInBackground(Integer... speed) {
int bottomMargin = contentLayoutParams.bottomMargin;
// 根据传入的速度来滚动界面,当滚动到达边界值时,跳出循环。
while (true) {
bottomMargin = bottomMargin + speed[0];
if (bottomMargin < -upMenuLayoutParams.height) {
bottomMargin = -upMenuLayoutParams.height;
break;
}
if (bottomMargin > 0) {
bottomMargin = 0;
break;
}
publishProgress(bottomMargin);
// 为了要有滚动效果产生,每次循环使线程睡眠一段时间,这样肉眼才能够看到滚动动画。
sleep(15);
}
if (speed[0] > 0) {
isUpMenuVisible = false;
} else {
isUpMenuVisible = true;
}
isSliding = false;
return bottomMargin;
}
@Override
protected void onProgressUpdate(Integer... bottomMargin) {
contentLayoutParams.bottomMargin = bottomMargin[0];
contentLayout.setLayoutParams(contentLayoutParams);
unFocusBindView();
}
@Override
protected void onPostExecute(Integer bottomMargin) {
contentLayoutParams.bottomMargin = bottomMargin;
contentLayout.setLayoutParams(contentLayoutParams);
}
}
class DownMenuScrollTask extends AsyncTask {
@Override
protected Integer doInBackground(Integer... speed) {
int topMargin = contentLayoutParams.topMargin;
// 根据传入的速度来滚动界面,当滚动到达边界值时,跳出循环。
while (true) {
topMargin = topMargin + speed[0];
if (topMargin < -downMenuLayoutParams.height) {
topMargin = -downMenuLayoutParams.height;
break;
}
if (topMargin > 0) {
topMargin = 0;
break;
}
publishProgress(topMargin);
// 为了要有滚动效果产生,每次循环使线程睡眠一段时间,这样肉眼才能够看到滚动动画。
sleep(15);
}
if (speed[0] > 0) {
isDownMenuVisible = false;
} else {
isDownMenuVisible = true;
}
isSliding = false;
return topMargin;
}
@Override
protected void onProgressUpdate(Integer... topMargin) {
contentLayoutParams.topMargin = topMargin[0];
contentLayout.setLayoutParams(contentLayoutParams);
unFocusBindView();
}
@Override
protected void onPostExecute(Integer topMargin) {
contentLayoutParams.topMargin = topMargin;
contentLayout.setLayoutParams(contentLayoutParams);
}
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void unFocusBindView() {
if (mBindView != null) {
mBindView.setPressed(false);
mBindView.setFocusable(false);
mBindView.setFocusableInTouchMode(false);
}
}
public void scrollToUpMenu() {
new UpMenuScrollTask().execute(-30);
}
public void scrollToDownMenu() {
new DownMenuScrollTask().execute(-30);
}
public void scrollToContentFromUpMenu() {
new UpMenuScrollTask().execute(30);
}
public void scrollToContentFromDownMenu() {
new DownMenuScrollTask().execute(30);
}
public boolean isUpLayoutVisible() {
return isUpMenuVisible;
}
public boolean isDownLayoutVisible() {
return isDownMenuVisible;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
// 获取上侧菜单布局对象
upMenuLayout = getChildAt(0);
upMenuLayoutParams = (MarginLayoutParams) upMenuLayout.getLayoutParams();
// 获取下侧菜单布局对象
downMenuLayout = getChildAt(1);
downMenuLayoutParams = (MarginLayoutParams) downMenuLayout.getLayoutParams();
// 获取内容布局对象
contentLayout = getChildAt(2);
contentLayoutParams = (RelativeLayout.LayoutParams) contentLayout.getLayoutParams();
contentLayoutParams.height = screenHeight;
contentLayout.setLayoutParams(contentLayoutParams);
}
}
private void recycleVelocityTracker() {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
下面是使用实例:
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.app.Activity;
public class MainActivity2 extends Activity {
private UpAndDownSlidinglayout updownSldingLayout;
private ListView contentList;
private LinearLayout ll;
private ArrayAdapter contentListAdapter;
private String[] contentItems = { "Content Item 1", "Content Item 2", "Content Item 3",
"Content Item 4", "Content Item 5", "Content Item 6", "Content Item 7",
"Content Item 8", "Content Item 9", "Content Item 10", "Content Item 11",
"Content Item 12", "Content Item 13", "Content Item 14", "Content Item 15",
"Content Item 16" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ll = (LinearLayout) findViewById(R.id.content);
updownSldingLayout = (UpAndDownSlidinglayout) findViewById(R.id.updown_sliding_layout);
contentList = (ListView) findViewById(R.id.contentList);
contentListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,
contentItems);
contentList.setAdapter(contentListAdapter);
updownSldingLayout.setScrollEvent(ll);
}
}
布局文件:
更多关于滑动功能的文章,请点击专题: 《Android滑动功能》
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。



