編輯:關於Android編程
首先這個控件應該是繼承ViewGroup:
初始化:
public class MyGroup extends ViewGroup{ private Scroller mScroller; private float mOriMotionX; private float mLastMotionX; private VelocityTracker mVelocityTracker; private int mTouchState = TOUCH_STATE_REST; private static final int TOUCH_STATE_REST = 0; private int mTouchSlop; private int mMaximumVelocity; private static final int TOUCH_STATE_SCROLLING = 1; private float mLastDownX; private static final int DEFAULT_VALUE = 1000; private int mNextScreen = -1; private boolean mFlagLimitUp = false; private static final int SNAP_VELOCITY = 700; private int mCurrentScreen; public MyGroup(Context context, AttributeSet attrs) { super(context, attrs); initWorkspace(); } private void initWorkspace() { mScroller = new Scroller(getContext()); setCurrentScreen(0); final ViewConfiguration configuration = ViewConfiguration .get(getContext()); mTouchSlop = configuration.getScaledTouchSlop();//這個是定義控件在scroll的最小像素距離 mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); //速率,fling的一個以每秒滑動多少像素的值 }
先重寫onmeasure:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int width = MeasureSpec.getSize(widthMeasureSpec); final int count = getChildCount(); for (int i = 0; i < count; i++) { getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } }
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int paddingleft = 0; int paddingTop = 0; int childLeft = paddingleft; final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != View.GONE) { final int childWidth = child.getMeasuredWidth(); final int childHeight = child.getMeasuredHeight() ; child.layout(childLeft, paddingTop, childLeft + childWidth, childHeight + paddingTop); childLeft += child.getMeasuredWidth(); //下個child的左邊距和第一個child的左邊距之間的距離正好是第一個child的width } } }
onInterceptTouchEvent只有返回false事件才會傳遞給控件裡的view,就是view的ontouch事件才可以捕捉 View裡的onTouchEvent返回為true,才能執行多次touch事件,事件才能得了傳遞
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); //如果為move事件,mTouchState為TOUCH_STATE_REST為靜止狀態,這個是防止子控件在滑動時又用手指去滑,這種情況下不響應這個事件 if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) { return true; } final float x = ev.getX(); switch (action) { case MotionEvent.ACTION_MOVE: final int xDiff = (int) Math.abs(x - mLastMotionX); final int touchSlop = mTouchSlop; boolean xMoved = xDiff > touchSlop; //如果xMoved為true表示手指在滑動 if (xMoved) { mTouchState = TOUCH_STATE_SCROLLING; } break; case MotionEvent.ACTION_DOWN: mLastMotionX = x; //mScroller.isFinished() 為true表示滑動結束了,這時候我們把狀態置為TOUCH_STATE_REST mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: mTouchState = TOUCH_STATE_REST; break; default: break; } //如果不是在靜止狀態,都返回true,這樣事件就不會傳遞給onTouchEvent了 return mTouchState != TOUCH_STATE_REST; }
@Override public boolean onTouchEvent(MotionEvent ev) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); int mScrollX = this.getScrollX(); //mScrollX表示X軸上的距離,往左滑動為正,這個時候屏幕向右移動 final int action = ev.getAction(); final float x = ev.getX(); final float y = ev.getY(); switch (action) { case MotionEvent.ACTION_DOWN: mOriMotionX = x; mLastMotionX = x; if (!mScroller.isFinished()) { mScroller.abortAnimation(); } mOriMotionX = x; mLastMotionX = x; mLastDownX = x; return true; case MotionEvent.ACTION_MOVE: System.out.println("====action move mScrollX="+mScrollX); final int buffer = getWidth() / 2; //這個表示在第一頁或是最後一頁還可以滑動半個屏幕 //如果是往後滑動,屏幕向前,那麼mLastMotionX是比x大的,deltaX是正的 int deltaX = (int) (mLastMotionX - x); mLastMotionX = x; System.out.println("=====deltaX="+deltaX); //deltaX<0表示往前滑動 if (deltaX < 0) { //這個是往右滑動,屏幕向左移動 scrollBy(Math.max(-mScrollX - buffer, deltaX), 0); }else{ int availableToScroll = 0; if (getChildCount() > 0) { //此時Workspace上可能未加任何item,count == 0 System.out.println("====rihgt="+(getChildAt( getChildCount() - 1).getRight())+"avail="+(getChildAt( getChildCount() - 1).getRight()- mScrollX - getWidth() )); //getChildAt(getChildCount() - 1).getRight()為所有的view加一起的寬度,這裡加了3個view,一個view為1080,則這個值為3240 availableToScroll = getChildAt( getChildCount() - 1).getRight() - mScrollX - getWidth(); //availableToScroll + buffer可以滑動的最大距離,deltax為滑動的距離 scrollBy(Math.min(availableToScroll + buffer, deltaX), 0); } } return true; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(DEFAULT_VALUE, mMaximumVelocity); int velocityX = (int) velocityTracker.getXVelocity(); //velocityX為手指滑動的速率,我們會跟給定值SNAP_VELOCITY做比較 if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) { // 這個時候是手指往前滑動,屏幕是向後移動 snapToScreen(mCurrentScreen - 1); } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) { // move right snapToScreen(mCurrentScreen + 1); } else { snapToDestination(mLastMotionX < mOriMotionX); } if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } mTouchState = TOUCH_STATE_REST; if (Math.abs(mLastDownX - x) > 10) { return true; } return false; case MotionEvent.ACTION_CANCEL: mTouchState = TOUCH_STATE_REST; return false; default: break; } return true; }
/**滑動的距離,離屏寬幾分之一時,就開始執行換屏動作。*/ /** * snapToDestination. * mLastMotionX < mOriMotionX (mLastMotion < mOriMotionX)表示這個是手向後滑動,但屏幕是往前的,反之是向前 * forward為true為往前劃動,這時將scrollX加上三分之二的屏幕的寬度 * scrollX / screenWidth 來決定當前在哪個屏幕 * @param forward 是前進還是後退. */ public void snapToDestination(boolean forward) { final int screenWidth = getWidth(); int scrollX = getScrollX(); if (forward) { scrollX += screenWidth - screenWidth / 3; } else { scrollX += screenWidth / 3; } System.out.println("======screenWidth="+screenWidth+"scrollX / screenWidth="+(scrollX / screenWidth)); snapToScreen(scrollX / screenWidth); } /** * 如果計算要滑動的距離:(whichScreen * getWidth())為滑動後的X坐標,this.getScrollX()為當前的坐標,兩者相減為滑動的距離 * Math.abs(delta) * 2為滑動的持續時間 */ public void snapToScreen(int whichScreen) { whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); boolean changingScreens = whichScreen != mCurrentScreen; mNextScreen = whichScreen; int mScrollX = this.getScrollX(); final int newX = whichScreen * getWidth(); final int delta = newX - mScrollX; System.out.println("====snapToScreen delta="+delta); mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta) * 2); //invalidate非常重要,不然你移動一點頁面不能回復原狀 invalidate(); }
第5節 BTChat本節開始介紹Arduino藍牙模塊,配合Android應用,實現一個藍牙聊天應用。5.1 什麼是藍牙簡單說就是一種不同設備之間點對點通訊的技術。有大篇
本文實例嘗試模仿實現Android標題顯示隱藏功能,通過給listview設置 mListView.setOnTouchListener 監聽 重寫ontouch方法 監
本篇文章接著上篇文章的內容來繼續討論View的繪制機制,上篇文章中我們主要講解了View的measure過程,今天我們就來學習ViewGroup的measur
android中,在進行耗時操作更新UI用到最多的方法就是Handler了,一般在子線程中進行耗時操作(訪問網絡等),然後發送消息到UI線程(主線程),使得界面得以更新。