- 浏览: 5819360 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (890)
- WindowsPhone (0)
- android (88)
- android快速迭代 (17)
- android基础 (34)
- android进阶 (172)
- android高级 (0)
- android拾遗 (85)
- android动画&效果 (68)
- Material Design (13)
- LUA (5)
- j2me (32)
- jQuery (39)
- spring (26)
- hibernate (20)
- struts (26)
- tomcat (9)
- javascript+css+html (62)
- jsp+servlet+javabean (14)
- java (37)
- velocity+FCKeditor (13)
- linux+批处理 (9)
- mysql (19)
- MyEclipse (9)
- ajax (7)
- wap (8)
- j2ee+apache (24)
- 其他 (13)
- phonegap (35)
最新评论
-
Memories_NC:
本地lua脚本终于执行成功了,虽然不是通过redis
java中调用lua脚本语言1 -
ZHOU452840622:
大神://处理返回的接收状态 这个好像没有监听到 遇 ...
android 发送短信的两种方式 -
PXY:
拦截部分地址,怎么写的for(int i=0;i<lis ...
判断是否登录的拦截器SessionFilter -
maotou1988:
Android控件之带清空按钮(功能)的AutoComplet ...
自定义AutoCompleteTextView -
yangmaolinpl:
希望有表例子更好。。。,不过也看明白了。
浅谈onInterceptTouchEvent、onTouchEvent与onTouch
我把SlidingDrawer源码提了出来,希望对1.5的朋友有帮助。
ATTRS.xml
用法布局main.xml:
panel很不错的一个抽屉控件
http://www.devstore.cn/code/info/587.html
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.SoundEffectConstants; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; public class SlidingDrawer extends ViewGroup { public static final int ORIENTATION_HORIZONTAL = 0; public static final int ORIENTATION_VERTICAL = 1; private static final int TAP_THRESHOLD = 6; private static final float MAXIMUM_TAP_VELOCITY = 100.0f; private static final float MAXIMUM_MINOR_VELOCITY = 150.0f; private static final float MAXIMUM_MAJOR_VELOCITY = 200.0f; private static final float MAXIMUM_ACCELERATION = 2000.0f; private static final int VELOCITY_UNITS = 1000; private static final int MSG_ANIMATE = 1000; private static final int ANIMATION_FRAME_DURATION = 1000 / 60; private static final int EXPANDED_FULL_OPEN = -10001; private static final int COLLAPSED_FULL_CLOSED = -10002; private final int mHandleId; private final int mContentId; private View mHandle; private View mContent; private final Rect mFrame = new Rect(); private final Rect mInvalidate = new Rect(); private boolean mTracking; private boolean mLocked; private VelocityTracker mVelocityTracker; private boolean mVertical; private boolean mExpanded; private int mBottomOffset; private int mTopOffset; private int mHandleHeight; private int mHandleWidth; private OnDrawerOpenListener mOnDrawerOpenListener; private OnDrawerCloseListener mOnDrawerCloseListener; private OnDrawerScrollListener mOnDrawerScrollListener; private final Handler mHandler = new SlidingHandler(); private float mAnimatedAcceleration; private float mAnimatedVelocity; private float mAnimationPosition; private long mAnimationLastTime; private long mCurrentAnimationTime; private int mTouchDelta; private boolean mAnimating; private boolean mAllowSingleTap; private boolean mAnimateOnClick; private final int mTapThreshold; private final int mMaximumTapVelocity; private final int mMaximumMinorVelocity; private final int mMaximumMajorVelocity; private final int mMaximumAcceleration; private final int mVelocityUnits; /** * Callback invoked when the drawer is opened. */ public static interface OnDrawerOpenListener { /** * Invoked when the drawer becomes fully open. */ public void onDrawerOpened(); } /** * Callback invoked when the drawer is closed. */ public static interface OnDrawerCloseListener { /** * Invoked when the drawer becomes fully closed. */ public void onDrawerClosed(); } /** * Callback invoked when the drawer is scrolled. */ public static interface OnDrawerScrollListener { /** * Invoked when the user starts dragging/flinging the drawer's handle. */ public void onScrollStarted(); /** * Invoked when the user stops dragging/flinging the drawer's handle. */ public void onScrollEnded(); } /** * Creates a new SlidingDrawer from a specified set of attributes defined in XML. * * @param context The application's environment. * @param attrs The attributes defined in XML. */ public SlidingDrawer(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** * Creates a new SlidingDrawer from a specified set of attributes defined in XML. * * @param context The application's environment. * @param attrs The attributes defined in XML. * @param defStyle The style to apply to this widget. */ public SlidingDrawer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingDrawer, defStyle, 0); int orientation = a.getInt(R.styleable.SlidingDrawer_orientation, ORIENTATION_VERTICAL); mVertical = orientation == ORIENTATION_VERTICAL; mBottomOffset = (int) a.getDimension(R.styleable.SlidingDrawer_bottomOffset, 0.0f); mTopOffset = (int) a.getDimension(R.styleable.SlidingDrawer_topOffset, 0.0f); mAllowSingleTap = a.getBoolean(R.styleable.SlidingDrawer_allowSingleTap, true); mAnimateOnClick = a.getBoolean(R.styleable.SlidingDrawer_animateOnClick, true); int handleId = a.getResourceId(R.styleable.SlidingDrawer_handle, 0); if (handleId == 0) { throw new IllegalArgumentException("The handle attribute is required and must refer " + "to a valid child."); } int contentId = a.getResourceId(R.styleable.SlidingDrawer_content, 0); if (contentId == 0) { throw new IllegalArgumentException("The content attribute is required and must refer " + "to a valid child."); } if (handleId == contentId) { throw new IllegalArgumentException("The content and handle attributes must refer " + "to different children."); } mHandleId = handleId; mContentId = contentId; final float density = getResources().getDisplayMetrics().density; mTapThreshold = (int) (TAP_THRESHOLD * density + 0.5f); mMaximumTapVelocity = (int) (MAXIMUM_TAP_VELOCITY * density + 0.5f); mMaximumMinorVelocity = (int) (MAXIMUM_MINOR_VELOCITY * density + 0.5f); mMaximumMajorVelocity = (int) (MAXIMUM_MAJOR_VELOCITY * density + 0.5f); mMaximumAcceleration = (int) (MAXIMUM_ACCELERATION * density + 0.5f); mVelocityUnits = (int) (VELOCITY_UNITS * density + 0.5f); a.recycle(); setAlwaysDrawnWithCacheEnabled(false); } @Override protected void onFinishInflate() { Log.i("tag", "===========onFinishInflate==========="); mHandle = findViewById(mHandleId); if (mHandle == null) { throw new IllegalArgumentException("The handle attribute is must refer to an" + " existing child."); } mHandle.setOnClickListener(new DrawerToggler()); mContent = findViewById(mContentId); if (mContent == null) { throw new IllegalArgumentException("The content attribute is must refer to an" + " existing child."); } // mContent.setVisibility(View.GONE); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.i("tag", "===========onMeasure==========="); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { throw new RuntimeException("SlidingDrawer cannot have UNSPECIFIED dimensions"); } final View handle = mHandle; measureChild(handle, widthMeasureSpec, heightMeasureSpec); if (mVertical) { int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset; mContent.measure(MeasureSpec.makeMeasureSpec(widthSpecSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); } else { int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset; mContent.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSpecSize, MeasureSpec.EXACTLY)); } setMeasuredDimension(widthSpecSize, heightSpecSize); } @Override protected void dispatchDraw(Canvas canvas) { final long drawingTime = getDrawingTime(); final View handle = mHandle; final boolean isVertical = mVertical; drawChild(canvas, handle, drawingTime); if (mTracking || mAnimating) { final Bitmap cache = mContent.getDrawingCache(); if (cache != null) { if (isVertical) { canvas.drawBitmap(cache, 0, handle.getBottom(), null); } else { canvas.drawBitmap(cache, handle.getRight(), 0, null); } } else { canvas.save(); canvas.translate(isVertical ? 0 : handle.getLeft() - mTopOffset, isVertical ? handle.getTop() - mTopOffset : 0); drawChild(canvas, mContent, drawingTime); canvas.restore(); } } else if (mExpanded) { drawChild(canvas, mContent, drawingTime); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { Log.i("tag", "===========onLayout==========="); if (mTracking) { return; } final int width = r - l; final int height = b - t; final View handle = mHandle; int childWidth = handle.getMeasuredWidth(); int childHeight = handle.getMeasuredHeight(); int childLeft; int childTop; final View content = mContent; if (mVertical) { childLeft = (width - childWidth) / 2; childTop = mExpanded ? mTopOffset : height - childHeight + mBottomOffset; content.layout(0, mTopOffset + childHeight, content.getMeasuredWidth(), mTopOffset + childHeight + content.getMeasuredHeight()); } else { childLeft = mExpanded ? mTopOffset : width - childWidth + mBottomOffset; childTop = (height - childHeight) / 2; content.layout(mTopOffset + childWidth, 0, mTopOffset + childWidth + content.getMeasuredWidth(), content.getMeasuredHeight()); } handle.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); mHandleHeight = handle.getHeight(); mHandleWidth = handle.getWidth(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (mLocked) { return false; } final int action = event.getAction(); float x = event.getX(); float y = event.getY(); final Rect frame = mFrame; final View handle = mHandle; handle.getHitRect(frame); if (!mTracking && !frame.contains((int) x, (int) y)) { return false; } if (action == MotionEvent.ACTION_DOWN) { mTracking = true; handle.setPressed(true); // Must be called before prepareTracking() prepareContent(); // Must be called after prepareContent() if (mOnDrawerScrollListener != null) { mOnDrawerScrollListener.onScrollStarted(); } if (mVertical) { final int top = mHandle.getTop(); mTouchDelta = (int) y - top; prepareTracking(top); } else { final int left = mHandle.getLeft(); mTouchDelta = (int) x - left; prepareTracking(left); } mVelocityTracker.addMovement(event); } return true; } @Override public boolean onTouchEvent(MotionEvent event) { if (mLocked) { return true; } if (mTracking) { mVelocityTracker.addMovement(event); final int action = event.getAction(); switch (action) { case MotionEvent.ACTION_MOVE: moveHandle((int) (mVertical ? event.getY() : event.getX()) - mTouchDelta); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(mVelocityUnits); float yVelocity = velocityTracker.getYVelocity(); float xVelocity = velocityTracker.getXVelocity(); boolean negative; final boolean vertical = mVertical; if (vertical) { negative = yVelocity < 0; if (xVelocity < 0) { xVelocity = -xVelocity; } if (xVelocity > mMaximumMinorVelocity) { xVelocity = mMaximumMinorVelocity; } } else { negative = xVelocity < 0; if (yVelocity < 0) { yVelocity = -yVelocity; } if (yVelocity > mMaximumMinorVelocity) { yVelocity = mMaximumMinorVelocity; } } float velocity = (float) Math.hypot(xVelocity, yVelocity); if (negative) { velocity = -velocity; } final int top = mHandle.getTop(); final int left = mHandle.getLeft(); if (Math.abs(velocity) < mMaximumTapVelocity) { if (vertical ? (mExpanded && top < mTapThreshold + mTopOffset) || (!mExpanded && top > mBottomOffset + getBottom() - getTop() - mHandleHeight - mTapThreshold) : (mExpanded && left < mTapThreshold + mTopOffset) || (!mExpanded && left > mBottomOffset + getRight() - getLeft() - mHandleWidth - mTapThreshold)) { if (mAllowSingleTap) { playSoundEffect(SoundEffectConstants.CLICK); if (mExpanded) { animateClose(vertical ? top : left); } else { animateOpen(vertical ? top : left); } } else { performFling(vertical ? top : left, velocity, false); } } else { performFling(vertical ? top : left, velocity, false); } } else { performFling(vertical ? top : left, velocity, false); } } break; } } return mTracking || mAnimating || super.onTouchEvent(event); } private void animateClose(int position) { prepareTracking(position); performFling(position, mMaximumAcceleration, true); } private void animateOpen(int position) { prepareTracking(position); performFling(position, -mMaximumAcceleration, true); } private void performFling(int position, float velocity, boolean always) { mAnimationPosition = position; mAnimatedVelocity = velocity; if (mExpanded) { if (always || (velocity > mMaximumMajorVelocity || (position > mTopOffset + (mVertical ? mHandleHeight : mHandleWidth) && velocity > -mMaximumMajorVelocity))) { // We are expanded, but they didn't move sufficiently to cause // us to retract. Animate back to the expanded position. mAnimatedAcceleration = mMaximumAcceleration; if (velocity < 0) { mAnimatedVelocity = 0; } } else { // We are expanded and are now going to animate away. mAnimatedAcceleration = -mMaximumAcceleration; if (velocity > 0) { mAnimatedVelocity = 0; } } } else { if (!always && (velocity > mMaximumMajorVelocity || (position > (mVertical ? getHeight() : getWidth()) / 2 && velocity > -mMaximumMajorVelocity))) { // We are collapsed, and they moved enough to allow us to expand. mAnimatedAcceleration = mMaximumAcceleration; if (velocity < 0) { mAnimatedVelocity = 0; } } else { // We are collapsed, but they didn't move sufficiently to cause // us to retract. Animate back to the collapsed position. mAnimatedAcceleration = -mMaximumAcceleration; if (velocity > 0) { mAnimatedVelocity = 0; } } } long now = SystemClock.uptimeMillis(); mAnimationLastTime = now; mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION; mAnimating = true; mHandler.removeMessages(MSG_ANIMATE); mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurrentAnimationTime); stopTracking(); } private void prepareTracking(int position) { mTracking = true; mVelocityTracker = VelocityTracker.obtain(); boolean opening = !mExpanded; if (opening) { mAnimatedAcceleration = mMaximumAcceleration; mAnimatedVelocity = mMaximumMajorVelocity; mAnimationPosition = mBottomOffset + (mVertical ? getHeight() - mHandleHeight : getWidth() - mHandleWidth); moveHandle((int) mAnimationPosition); mAnimating = true; mHandler.removeMessages(MSG_ANIMATE); long now = SystemClock.uptimeMillis(); mAnimationLastTime = now; mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION; mAnimating = true; } else { if (mAnimating) { mAnimating = false; mHandler.removeMessages(MSG_ANIMATE); } moveHandle(position); } } private void moveHandle(int position) { final View handle = mHandle; if (mVertical) { if (position == EXPANDED_FULL_OPEN) { handle.offsetTopAndBottom(mTopOffset - handle.getTop()); invalidate(); } else if (position == COLLAPSED_FULL_CLOSED) { handle.offsetTopAndBottom(mBottomOffset + getBottom() - getTop() - mHandleHeight - handle.getTop()); invalidate(); } else { final int top = handle.getTop(); int deltaY = position - top; if (position < mTopOffset) { deltaY = mTopOffset - top; } else if (deltaY > mBottomOffset + getBottom() - getTop() - mHandleHeight - top) { deltaY = mBottomOffset + getBottom() - getTop() - mHandleHeight - top; } handle.offsetTopAndBottom(deltaY); final Rect frame = mFrame; final Rect region = mInvalidate; handle.getHitRect(frame); region.set(frame); region.union(frame.left, frame.top - deltaY, frame.right, frame.bottom - deltaY); region.union(0, frame.bottom - deltaY, getWidth(), frame.bottom - deltaY + mContent.getHeight()); invalidate(region); } } else { if (position == EXPANDED_FULL_OPEN) { handle.offsetLeftAndRight(mTopOffset - handle.getLeft()); invalidate(); } else if (position == COLLAPSED_FULL_CLOSED) { handle.offsetLeftAndRight(mBottomOffset + getRight() - getLeft() - mHandleWidth - handle.getLeft()); invalidate(); } else { final int left = handle.getLeft(); int deltaX = position - left; if (position < mTopOffset) { deltaX = mTopOffset - left; } else if (deltaX > mBottomOffset + getRight() - getLeft() - mHandleWidth - left) { deltaX = mBottomOffset + getRight() - getLeft() - mHandleWidth - left; } handle.offsetLeftAndRight(deltaX); final Rect frame = mFrame; final Rect region = mInvalidate; handle.getHitRect(frame); region.set(frame); region.union(frame.left - deltaX, frame.top, frame.right - deltaX, frame.bottom); region.union(frame.right - deltaX, 0, frame.right - deltaX + mContent.getWidth(), getHeight()); invalidate(region); } } } private void prepareContent() { if (mAnimating) { return; } // Something changed in the content, we need to honor the layout request // before creating the cached bitmap final View content = mContent; if (content.isLayoutRequested()) { if (mVertical) { final int childHeight = mHandleHeight; int height = getBottom() - getTop() - childHeight - mTopOffset; content.measure(MeasureSpec.makeMeasureSpec(getRight() - getLeft(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); content.layout(0, mTopOffset + childHeight, content.getMeasuredWidth(), mTopOffset + childHeight + content.getMeasuredHeight()); } else { final int childWidth = mHandle.getWidth(); int width = getRight() - getLeft() - childWidth - mTopOffset; content.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getBottom() - getTop(), MeasureSpec.EXACTLY)); content.layout(childWidth + mTopOffset, 0, mTopOffset + childWidth + content.getMeasuredWidth(), content.getMeasuredHeight()); } } // Try only once... we should really loop but it's not a big deal // if the draw was cancelled, it will only be temporary anyway content.getViewTreeObserver().dispatchOnPreDraw(); content.buildDrawingCache(); // content.setVisibility(View.GONE); } private void stopTracking() { mHandle.setPressed(false); mTracking = false; if (mOnDrawerScrollListener != null) { mOnDrawerScrollListener.onScrollEnded(); } if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } private void doAnimation() { if (mAnimating) { incrementAnimation(); if (mAnimationPosition >= mBottomOffset + (mVertical ? getHeight() : getWidth()) - 1) { mAnimating = false; closeDrawer(); } else if (mAnimationPosition < mTopOffset) { mAnimating = false; openDrawer(); } else { moveHandle((int) mAnimationPosition); mCurrentAnimationTime += ANIMATION_FRAME_DURATION; mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurrentAnimationTime); } } } private void incrementAnimation() { long now = SystemClock.uptimeMillis(); float t = (now - mAnimationLastTime) / 1000.0f; // ms -> s final float position = mAnimationPosition; final float v = mAnimatedVelocity; // px/s final float a = mAnimatedAcceleration; // px/s/s mAnimationPosition = position + (v * t) + (0.5f * a * t * t); // px mAnimatedVelocity = v + (a * t); // px/s mAnimationLastTime = now; // ms } /** * Toggles the drawer open and close. Takes effect immediately. * * @see #open() * @see #close() * @see #animateClose() * @see #animateOpen() * @see #animateToggle() */ public void toggle() { if (!mExpanded) { openDrawer(); } else { closeDrawer(); } invalidate(); requestLayout(); } /** * Toggles the drawer open and close with an animation. * * @see #open() * @see #close() * @see #animateClose() * @see #animateOpen() * @see #toggle() */ public void animateToggle() { if (!mExpanded) { animateOpen(); } else { animateClose(); } } /** * Opens the drawer immediately. * * @see #toggle() * @see #close() * @see #animateOpen() */ public void open() { openDrawer(); invalidate(); requestLayout(); sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } /** * Closes the drawer immediately. * * @see #toggle() * @see #open() * @see #animateClose() */ public void close() { closeDrawer(); invalidate(); requestLayout(); } /** * Closes the drawer with an animation. * * @see #close() * @see #open() * @see #animateOpen() * @see #animateToggle() * @see #toggle() */ public void animateClose() { prepareContent(); final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener; if (scrollListener != null) { scrollListener.onScrollStarted(); } animateClose(mVertical ? mHandle.getTop() : mHandle.getLeft()); if (scrollListener != null) { scrollListener.onScrollEnded(); } } /** * Opens the drawer with an animation. * * @see #close() * @see #open() * @see #animateClose() * @see #animateToggle() * @see #toggle() */ public void animateOpen() { prepareContent(); final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener; if (scrollListener != null) { scrollListener.onScrollStarted(); } animateOpen(mVertical ? mHandle.getTop() : mHandle.getLeft()); sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); if (scrollListener != null) { scrollListener.onScrollEnded(); } } private void closeDrawer() { moveHandle(COLLAPSED_FULL_CLOSED); // mContent.setVisibility(View.GONE); mContent.destroyDrawingCache(); if (!mExpanded) { return; } mExpanded = false; if (mOnDrawerCloseListener != null) { mOnDrawerCloseListener.onDrawerClosed(); } } private void openDrawer() { moveHandle(EXPANDED_FULL_OPEN); // mContent.setVisibility(View.VISIBLE); if (mExpanded) { return; } mExpanded = true; if (mOnDrawerOpenListener != null) { mOnDrawerOpenListener.onDrawerOpened(); } } /** * Sets the listener that receives a notification when the drawer becomes open. * * @param onDrawerOpenListener The listener to be notified when the drawer is opened. */ public void setOnDrawerOpenListener(OnDrawerOpenListener onDrawerOpenListener) { mOnDrawerOpenListener = onDrawerOpenListener; } /** * Sets the listener that receives a notification when the drawer becomes close. * * @param onDrawerCloseListener The listener to be notified when the drawer is closed. */ public void setOnDrawerCloseListener(OnDrawerCloseListener onDrawerCloseListener) { mOnDrawerCloseListener = onDrawerCloseListener; } /** * Sets the listener that receives a notification when the drawer starts or ends * a scroll. A fling is considered as a scroll. A fling will also trigger a * drawer opened or drawer closed event. * * @param onDrawerScrollListener The listener to be notified when scrolling * starts or stops. */ public void setOnDrawerScrollListener(OnDrawerScrollListener onDrawerScrollListener) { mOnDrawerScrollListener = onDrawerScrollListener; } /** * Returns the handle of the drawer. * * @return The View reprenseting the handle of the drawer, identified by * the "handle" id in XML. */ public View getHandle() { return mHandle; } /** * Returns the content of the drawer. * * @return The View reprenseting the content of the drawer, identified by * the "content" id in XML. */ public View getContent() { return mContent; } /** * Unlocks the SlidingDrawer so that touch events are processed. * * @see #lock() */ public void unlock() { mLocked = false; } /** * Locks the SlidingDrawer so that touch events are ignores. * * @see #unlock() */ public void lock() { mLocked = true; } /** * Indicates whether the drawer is currently fully opened. * * @return True if the drawer is opened, false otherwise. */ public boolean isOpened() { return mExpanded; } /** * Indicates whether the drawer is scrolling or flinging. * * @return True if the drawer is scroller or flinging, false otherwise. */ public boolean isMoving() { return mTracking || mAnimating; } private class DrawerToggler implements OnClickListener { public void onClick(View v) { if (mLocked) { return; } // mAllowSingleTap isn't relevant here; you're *always* // allowed to open/close the drawer by clicking with the // trackball. if (mAnimateOnClick) { animateToggle(); } else { toggle(); } } } private class SlidingHandler extends Handler { public void handleMessage(Message m) { switch (m.what) { case MSG_ANIMATE: doAnimation(); break; } } } }
ATTRS.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="SlidingDrawer"> <attr name="orientation"> <enum name="horizontal" value="0" /> <enum name="vertical" value="1" /> </attr> <attr name="content" format="reference" /> <attr name="handle" format="reference" /> <attr name="bottomOffset" format="dimension" /> <attr name="topOffset" format="dimension" /> <attr name="allowSingleTap" format="boolean" /> <attr name="animateOnClick" format="boolean" /> </declare-styleable> </resources>
用法布局main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/com.ql.app" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#808080" > <com.ql.app.SlidingDrawer android:id="@+id/slidingdrawer" android:layout_width="fill_parent" android:layout_height="fill_parent" app:orientation="vertical" app:handle="@+id/handle" app:content="@+id/content" app:topOffset="100dip" > <Button android:id="@+id/handle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="handle" /> <LinearLayout android:id="@+id/content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#00ff00"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" /> <EditText android:id="@+id/editText" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> </com.ql.app.SlidingDrawer> </LinearLayout>
panel很不错的一个抽屉控件
http://www.devstore.cn/code/info/587.html
发表评论
-
http://www.android-studio.org/
2018-08-06 09:25 0http://www.android-studio.org/ ... -
简单拖动效果(带Cache,需要完善)
2011-10-13 15:10 4227如何去实现一个具有幻象的拖拽效果? 所谓”幻象“就是当你按下去 ... -
Android Activity中启动另一应用程序的方法,无需得到类名
2011-08-02 14:46 17256在网上搜索了一会相关的实现代码,发现所有的文章都说是需要包名和 ... -
java-universal-tween-engine,一个动画系统库
2011-06-29 09:21 6742http://code.google.com/p/java-u ... -
网上发现的一个android UI包
2011-05-24 12:21 4093里面有些UI和效果 -
android中使用代码启动其他程序
2011-04-29 23:15 5285你要訪問其他的程序,那麼這個程序要先裝載到模擬器或真機上面,因 ... -
listView背景问题以及限制editText字数以及如果想通知别人已经不能在写
2011-04-29 22:44 32091.在listView设置好背景之后 你如果点击空白出 你会发 ... -
Android键盘和触摸事件处理
2011-04-29 22:32 7003activity和VIEW都能接收触摸和按键,如果响应事件只需 ... -
Android的绘制文本对象FontMetrics的介绍及绘制文本
2011-04-29 22:29 11489一。Android绘制文本对象FontMetrics介绍 ... -
Android View 拖动&插入
2011-04-29 22:20 3546View 拖动&插入 即: 支持 拖动图标 然后 ... -
使TextView文本可以水平和垂直滚动
2011-04-29 21:59 14426在做一个小的电子书程序,要求电子书具有放大缩小的功能,所以肯定 ... -
ArrayAdapter源码
2011-04-29 12:29 6300看看人家怎么写的。 /* * Copyright (C ... -
Android下获取开机时间
2011-04-02 21:51 6226找了一圈没发现能得到开机启动时间资料,于是乎突发奇想,得到了解 ... -
AutoCompleteTextView连接到数据库
2011-03-30 20:49 4727AutoCompleteTextView可以根据输入 ... -
改变屏幕Brightness(亮度)
2011-03-30 12:48 4603http://www.eoeandroid.com/forum ... -
android 拖拽图片&拖动浮动按钮到处跑
2011-02-24 20:55 31771来自老外: import android.app.Acti ... -
拖动一个控件在另一个控件(layout)上,并固定位置在几个位置显示
2011-02-24 20:51 5893实现效果: 鼠标拖动btn SSS,SSS在水平的layo ... -
Handler与Message类,实现n秒后无操作自动消失功能
2011-02-24 20:45 4638实现功能:某控件不操作10秒后,自动消失。如照相机变焦条出现后 ... -
带删除按钮的ListView
2011-02-24 10:33 6146不用说了,上图先: import java.util.A ... -
android3.0之Action Bar基础
2011-02-22 17:12 6828http://www.android123.com.cn/an ...
相关推荐
这个压缩包“安卓SlidingDrawer抽屉控件源码.zip”提供了这样一个控件的示例代码,对于初学者来说是一个很好的学习资源。 首先,我们来理解一下SlidingDrawer的基本概念。SlidingDrawer控件通常包含两个部分:一个...
本项目源码实例"SlidingDrawer"是针对这一需求的具体实现,旨在帮助开发者更好地理解和运用Android抽屉效果。 首先,SlidingDrawer是Android SDK提供的一种原生组件,它允许用户通过手势从屏幕边缘滑出一个隐藏的...
3. **源码分析**:理解SlidingDrawer的源码有助于自定义行为,解决兼容性问题,以及优化性能。 4. **博客文章**:提供了关于SlidingDrawer的使用和源码分析,是学习和解决问题的重要资源。 5. **示例项目**:...
为了实现四向滑动,我们需要对SlidingDrawer的源码进行修改。以下是一些关键步骤: 1. **扩展SlidingDrawer类**:创建一个新的自定义View类,继承自SlidingDrawer,并重写其中的相关方法,比如onTouchEvent(),以...
Aj_01 来自:http://blog.csdn.net/Android_Tutor/archive/2010/04/14/5486804.aspx 测试:Android Launcher抽屉类SlidingDrawer的使用!
在提供的`DemoSlidingDrawer`压缩包文件中,可能包含了实现这一功能的完整项目源码。解压后,我们可以看到`res/layout/main.xml`布局文件的详细设置,以及`MainActivity.java`中对`SlidingDrawer`的控制逻辑。通过...
文件"06SlidingDrawer"可能是这个代码实例的源码,你可以查看这个文件来了解具体的实现细节,包括如何布局handle和content,以及如何处理触摸事件和滑动动画。通过学习这个实例,开发者可以更好地理解和掌握`...
2. **Android Sliding Drawer组件**:虽然在新的Material Design规范中已不再推荐使用SlidingDrawer,但了解其工作原理对理解现在的DrawerLayout仍然有帮助。 3. **DrawerLayout**:目前,Android推荐使用...
在源码中,我们可以看到SlidingDrawer的实现主要依赖于OnTouchListener和ViewDragHelper。OnTouchListener监听用户的触摸事件,判断是开始拖动还是滑动,然后调用ViewDragHelper来处理抽屉的滑动动画。...
抽屉效果的实现,是通过Android SDK中的SlidingDrawer或者DrawerLayout组件来完成的。本篇文章将深入解析“应用源码之抽屉效果Demo源码”,帮助开发者更好地理解和应用这一功能。 首先,我们来看抽屉效果的基础概念...
源码可能包含对SlidingDrawer或NavigationView的实现,展示如何实现手势滑动触发菜单显示和隐藏。 4. **ViewPager与TabLayout**:用于实现多页滑动效果,源码可能包含了使用ViewPager配合TabLayout创建滑动标签页的...
7. **侧边栏滑动**:这种设计通常使用SlidingDrawer或SlideOutMenu等库来实现,它提供了一种常见的Android应用导航方式,可以帮助开发者了解如何创建滑动菜单。 8. **AidlDemo(简单aidl的例子)**:这个简单的AIDL...
滑动选择器(SlidingDrawer)或底部导航栏(BottomNavigationView)则提供了更丰富的交互体验。此外,还有诸如SwipeRefreshLayout(用于实现下拉刷新)和FloatingActionButton(悬浮操作按钮)等流行组件。示例源码...
在本案例中,我们将深入探讨安卓SlidingDrawer控件的使用及其源码解析。 首先,让我们理解SlidingDrawer的基本结构。它主要由两部分组成:handle(手柄)和content(内容)。handle是用户拖动的可视元素,而content...
通过研究这个源码,开发者不仅可以掌握`SlidingDrawer`组件的用法,还能了解到触摸事件处理、动画实现以及通知管理等方面的知识。对于想要提升Android UI设计和交互体验的开发者来说,这是一个不容错过的学习案例。
通过使用`SlidingDrawer`组件或自定义布局,开发者可以创建滑动触发的菜单效果。 3. **底部导航栏(Bottom Navigation)**:Android Material Design规范推荐的底部导航栏,它允许用户在三个到五个主要功能之间切换。...
Android的SlidingDrawer和SlideOut Drawer库提供了实现方法。源码中可能有这些组件的实现,展示了如何在主界面边缘滑动时显示隐藏的菜单。 4. **下拉刷新与上拉加载**:Pull-to-Refresh和Load-More效果在列表和滚动...
通过学习和研究这个压缩包中的源码,开发者不仅可以掌握旧版`SlidingDrawer`的使用,还能了解到如何使用更现代的`DrawerLayout`和`NavigationView`来创建更符合当前设计趋势的侧滑菜单。无论是对于初学者还是有经验...
这种效果可以通过使用Android的`SlidingDrawer`组件(已过时)或者第三方库如`Android Sliding Up Panel`,`SlideMenu`,`Android Design Support Library`中的`NavigationView`来实现。但自定义控件可以让我们更...