最近要做一个类似Path、海豚浏览器、人人那样的横向侧滑导航栏 这个效果最早应该是在pad上用的比较多,现在手机端也逐渐开始流行起来了,但是发现网上没有相关资料,不太清楚具体是怎么实现的,开始觉得是用SlidingDrawer抽屉做的,但是发现抽屉没办法在收起的时候多留出一块,只能在收起时完全隐藏,同时在拉出抽屉时下面的页面是保持不动,不像海豚浏览器的收藏页面,有那种页面顶出屏幕的效果。
不知道哪位高手做过这个效果,能否分享一下或者给点思路,谢谢啦~~
不知道哪位高手做过这个效果,能否分享一下或者给点思路,谢谢啦~~
解决方案 »
- android系统访问web站点出现404的问题
- android R中的integer类
- 求教android换肤
- 高分求助GPS获取到的经纬度,绘制到google map上出错--android2.1
- 关于用PC控制android平台?droid VNC server 和screen cast?
- 请教:eclipse总是崩溃
- 懂GUI的MY欢迎指教, DPI 问题
- phonegap 支持播放视频吗?
- R报红是什么意思呀?
- 将 byte[]数据写成一个语音文件 pcm 格式,或者wav 格式 ,或者avi格式
- 请帮看下下面的Hello World怎么也报错啊?
- 关于android 中的GPRS问题
如果这样的话就相当于要做一个比手机屏幕大的多的xml布局吧,然后用ScrollView滑动布局,来显示在屏幕上?这样的话用户可以随意滑动到布局的任意位置,不能实现 只允许滑动到上面图片里的那3个指定位置的效果
看来要重写下ScrollView了先试试吧,谢啦
/**
* 包裹在该布局内部的子视图可以左右滑动<br>
* @author http://blog.csdn.net/Yao_GUET date: 2011-05-04
*/
public class HorizonalScrollLayout extends LinearLayout {
/**
* 通过Handler将滑屏结果通知使用该滑屏控件的Activity<br>
* 必须先调用<br><code>public void setHandler(Handler handler) </code><br>来设置handler.返回的消息为:<br>
* <code>
* Message msg = new Message();<br>
msg.what = ON_SCROLL_CHANGED_MESSAGE_WHAT;<br>
msg.arg1 = whichScreen;//滑到的目标屏幕索引(0为第一个屏幕)<br>
handler.sendMessage(msg);<br>
*
* </code>
*/
public static final int ON_SCROLL_CHANGED_MESSAGE_WHAT = 2087; private static final String TAG = "HorizonalScrollLayout";
private Scroller mScroller;
private VelocityTracker mVelocityTracker; private int mCurScreen;
private int mDefaultScreen = 0; private static final int TOUCH_STATE_REST = 0;
private static final int TOUCH_STATE_SCROLLING = 1; private static final int SNAP_VELOCITY = 600; private int mTouchState = TOUCH_STATE_REST;
private int mTouchSlop;
private float mLastMotionX;
private float mLastMotionY;
private OnSnapDestinationListener onSnapDestinationListener;
Handler handler ;
public HorizonalScrollLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context); mCurScreen = mDefaultScreen;
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// if (changed) { //如果不注释掉,里面的ListView显示出不来
int childLeft = 0;
final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) {
final View childView = getChildAt(i);
if (childView.getVisibility() != View.GONE) {
final int childWidth = childView.getMeasuredWidth();
childView.layout(childLeft, 0, childLeft + childWidth, childView
.getMeasuredHeight());
childLeft += childWidth;
}
}
// }
} @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("ScrollLayout only canmCurScreen run at EXACTLY mode!");
} final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("ScrollLayout only can run at EXACTLY mode!");
} // The children are given the same width and height as the scrollLayout
final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
// Log.e(TAG, "moving to screen "+mCurScreen);
scrollTo(mCurScreen * width, 0);
}
public void setOnSnapDestinationListener(OnSnapDestinationListener onSnapDestinationListener) {
this.onSnapDestinationListener = onSnapDestinationListener;
} /**
* According to the position of current layout scroll to the destination
* page.
*/
public void snapToDestination() {
final int screenWidth = getWidth();
final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;
snapToScreen(destScreen);
} public void snapToScreen(int whichScreen) {
int tmp = mCurScreen;
// get the valid layout page
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
if (getScrollX() != (whichScreen * getWidth())) {
final int delta = whichScreen * getWidth() - getScrollX();
mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta));
mCurScreen = whichScreen;
invalidate(); // Redraw the layout
}
if(tmp == whichScreen){
return;
}
if(handler!= null){
Message msg = new Message();
msg.what = ON_SCROLL_CHANGED_MESSAGE_WHAT;
msg.arg1 = whichScreen;
handler.sendMessage(msg);
}
} public void setToScreen(int whichScreen) {
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
mCurScreen = whichScreen;
scrollTo(whichScreen * getWidth(), 0);
invalidate();
} public int getCurScreen() {
return mCurScreen;
} @Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
} @Override
public boolean onTouchEvent(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event); final int action = event.getAction();
final float x = event.getX();
final float y = event.getY(); switch (action) {
case MotionEvent.ACTION_DOWN:
// Log.e(TAG, "event down!");
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionX = x;
break; case MotionEvent.ACTION_MOVE:
int deltaX = (int) (mLastMotionX - x);
mLastMotionX = x; scrollBy(deltaX, 0);
break; case MotionEvent.ACTION_UP:
// Log.e(TAG, "event : up");
// if (mTouchState == TOUCH_STATE_SCROLLING) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000);
int velocityX = (int) velocityTracker.getXVelocity();// Log.e(TAG, "velocityX:" + velocityX); if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {
// Fling enough to move left
// Log.e(TAG, "snap left");
if(onSnapDestinationListener == null || onSnapDestinationListener.isAbleToSnap())
snapToScreen(mCurScreen - 1);
else
snapToScreen(mCurScreen);
} else if (velocityX < -SNAP_VELOCITY && mCurScreen < getChildCount() - 1) {
// Fling enough to move right
// Log.e(TAG, "snap right");
if(onSnapDestinationListener == null || onSnapDestinationListener.isAbleToSnap())
snapToScreen(mCurScreen + 1);
else
snapToScreen(mCurScreen);
} else {
snapToDestination();
} if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
// }
mTouchState = TOUCH_STATE_REST;
break;
case MotionEvent.ACTION_CANCEL:
mTouchState = TOUCH_STATE_REST;
break;
} return true;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Log.e(TAG, "onInterceptTouchEvent-slop:" + mTouchSlop); 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:
/*
* 2011.12.29
* 如果内部的子视图有ScrollView,当用户在ScrollView上下滑动的时候,判断如果Y轴变化值大于X轴变化的1.2倍,就不要消费这个事件了
* 否则会导致用户本来是想上下滑动ScrollView 结果这个滑动事件被本视图吸收了,变为左右滑动
*/
int deltaX = (int) (mLastMotionX - x);
int deltaY = (int) (mLastMotionY - y);
if(Math.abs(deltaY) > Math.abs(deltaX * 1.2)){
return false;
}
/*
* =========================================
*/
final int xDiff = (int) Math.abs(mLastMotionX - x);
if (xDiff > mTouchSlop) {
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;
}
public interface OnSnapDestinationListener{
/**
* 当滑到目标屏幕的时间发生之前调用,如果返回false;则不继续
* @return
* @author : wang.jun<br>
* @time : Mar 12, 2012 4:17:24 PM<br>
*/
public boolean isAbleToSnap();
}}
网上找到了一个Demo,这个Demo很接近这个效果了,可以借鉴下它的思路
http://download.csdn.net/detail/wzy820715/4376117