但是很多大家所熟知的控件在內部都是使用Scroller來實現的,如ViewPager、ListView等。
scrollBy方法
scrollTo方法
x:X軸(水平)方向移動到目的座標。正值向左移動,負值向右移動,單位是像素。
y:Y軸(垂直)方向移動到目的座標。正值向上移動,負值向下移動,單位是像素。
總結:
移動是反的和座標系
view裏面有scrollTo方法
layout_wx_sync_btn.scrollBy(100,100); share_newsport_layout.scrollBy(100,100);
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());//回彈的效果,會移動
mScroller.startScroll(getScrollX(), 0, dx, 0);
public void computeScroll() {}
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());//回彈的效果,會移動
Scroller 的 getCurX()
和 getCurY()
來獲取當前時刻 View 應該滾動的位置
public class ScollerActivity extends Activity { private ScrollerLayout scrollerLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_scoller); scrollerLayout = (ScrollerLayout) findViewById(R.id.activity_marginlayout_scrollerlayout); /** * 動態添加view */ scrollerLayout.removeAllViewsInLayout(); for (int i = 0; i < 3; i++) { TextView textView = new TextView(this); textView.setBackgroundColor(Color.RED); textView.setTextColor(Color.WHITE); textView.setClickable(true); ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300); textView.setText("Scroller滑動Demo-" + "TextView-" + (i + 1)); textView.setGravity(Gravity.CENTER); textView.setLayoutParams(layoutParams); scrollerLayout.addView(textView); } } }
public class ScrollerLayout extends ViewGroup { /** * 用於完成滾動操作的實例 */ private Scroller mScroller; /** * 判定爲拖動的最小移動像素數 */ private int mTouchSlop; /** * 手機按下時的屏幕座標 */ private float mXDown; /** * 手機當時所處的屏幕座標 */ private float mXMove; /** * 上次觸發ACTION_MOVE事件時的屏幕座標 */ private float mXLastMove; /** * 界面可滾動的左邊界 */ private int leftBorder; /** * 界面可滾動的右邊界 */ private int rightBorder; public ScrollerLayout(Context context, AttributeSet attrs) { super(context, attrs); // 第一步,創建Scroller的實例 mScroller = new Scroller(context); ViewConfiguration configuration = ViewConfiguration.get(context); // 獲取TouchSlop值 /*** * 這個值在後面將用於判斷當前用戶的操作是否是拖動。 */ mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); } /*** * viewGroup的測量方式 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); // 爲ScrollerLayout中的每一個子控件測量大小 measureChild(childView, widthMeasureSpec, heightMeasureSpec); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); // 爲ScrollerLayout中的每一個子控件在水平方向上進行佈局 childView.layout(i * childView.getMeasuredWidth(), 0, (i + 1) * childView.getMeasuredWidth(), childView.getMeasuredHeight()); } // 初始化左右邊界值 leftBorder = getChildAt(0).getLeft();//第一個控件的左邊 rightBorder = getChildAt(getChildCount() - 1).getRight();//最後一個控件的右邊 } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mXDown = ev.getRawX();//相對屏幕的距離 mXLastMove = mXDown; Log.d("peng","onInterceptTouchEvent ACTION_DOWN "); break; case MotionEvent.ACTION_MOVE: mXMove = ev.getRawX(); float diff = Math.abs(mXMove - mXDown); mXLastMove = mXMove; // 當手指拖動值大於TouchSlop值時,認爲應該進行滾動,攔截子控件的事件 if (diff > mTouchSlop) { Log.w("peng","diff > mTouchSlop"+mXMove+"mXLastMove:"+mXLastMove); return true; } Log.d("peng","onInterceptTouchEventACTION_MOVE "); break; } return super.onInterceptTouchEvent(ev); } /** * * getScrollX(); * 當前View視圖左上角座標與View視圖初始位置x軸方向上的距離。 * * * 那麼當我們把事件攔截掉之後,就會將事件交給ScrollerLayout的onTouchEvent()方法來處理 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: mXMove = event.getRawX();//觸摸點距離x的距離 Log.i("peng","onTouchEvent_ACTION_MOVE"+mXMove); //mXLastMove 開始拖動的距離 //mXMove 移動的距離 int scrolledX = (int) (mXLastMove - mXMove); //不添加會滑出去 if (getScrollX() + scrolledX < leftBorder) { scrollTo(leftBorder, 0);// 左邊-------左邊邊界條件,移動 Log.w("peng","scrollTo left"+leftBorder+"scrolledX="+scrolledX+"getScrollX();"+getScrollX()); return true; } else if (getScrollX() + getWidth() + scrolledX > rightBorder) { scrollTo(rightBorder - getWidth(), 0);//-------右邊邊界條件 Log.w("peng","scrollTo right"+rightBorder); return true; } scrollBy(scrolledX, 0);//移動的差值就是滾動的距離 mXLastMove = mXMove; break; case MotionEvent.ACTION_UP: // 當手指擡起時,根據當前的滾動值來判定應該滾動到哪個子控件的界面 int targetIndex = (getScrollX() + getWidth() / 2) / getWidth(); int dx = targetIndex * getWidth() - getScrollX(); // 第二步,調用startScroll()方法來初始化滾動數據並刷新界面 /** * 回彈,滾動到哪個位置 */ mScroller.startScroll(getScrollX(), 0, dx, 0); Log.d("peng","onTouchEventACTION_UP"); invalidate(); break; } return super.onTouchEvent(event); } /** * 手滑動停止 */ @Override public void computeScroll() { // 第三步,重寫computeScroll()方法,並在其內部完成平滑滾動的邏輯 if (mScroller.computeScrollOffset()) { Log.d("peng","computeScroll"); scrollTo(mScroller.getCurrX(), mScroller.getCurrY());//回彈的效果,會移動 invalidate(); } } }
https://blog.csdn.net/weixin_37730482/article/details/80649317