ViewGroup重写——滚动页面容器

来源:互联网 发布:js获取input file路径 编辑:程序博客网 时间:2024/06/04 19:27

滚动页面容器

  • 子控件水平排列
  • 子控件之间可以相互滚动切换
  • 松开手指可以自动前后切换
比如像ViewPager一样,跟随手势滚动,松开手指可以自动判断滚动到上一个还是下一个。如图。

重写onLayout指定子控件的位置,重写onTouchEvent处理触摸事件,实现onGestureListener接口,处理scroll事件。
onLayout的规则就很简单了,高不变,宽按照个数叠加就可以了
getChildAt(i).layout(getWidth() * i, 0, getWidth() * (i + 1), getHeight());
onTouchEvent中使用,GestureListener 的onTouchEvent(event)就可以自动处理好多事件,比如onDown,onScroll,onLongPress等。
松开手指用一个帮助类来计算时间差,并不断的调用computeScroll来实现自动缓慢滚动。

容器类PagedView
public class PagedView extends ViewGroup implements OnGestureListener {private final String TAG = "PagedView";private final boolean DEBUG = false;private int mCurrentIndex;private float mDownX;private DistanceHelper mDistanceHelper;GestureDetector detector = new GestureDetector(getContext(), this);public PagedView(Context context) {this(context, null);}public PagedView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public PagedView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mDistanceHelper = new DistanceHelper(getContext());}protected void onLayout(boolean changed, int l, int t, int r, int b) {int count = getChildCount();for (int i = 0; i < count; i++) {getChildAt(i).layout(getWidth() * i, 0, getWidth() * (i + 1), getHeight());}}@Overridepublic boolean onTouchEvent(MotionEvent event) {detector.onTouchEvent(event);//调用之后会自动处理手势switch (event.getAction()) {case MotionEvent.ACTION_UP:// Log.i(TAG, "up");int tmpId = 0;if ((event.getX() - mDownX) > getWidth() / 2) {tmpId = mCurrentIndex - 1;} else if (mDownX - event.getX() > getWidth() / 2) {tmpId = mCurrentIndex + 1;} else {tmpId = mCurrentIndex;}int childCount = getChildCount();mCurrentIndex = tmpId < 0 ? 0 : (tmpId > childCount - 1 ? childCount - 1 : tmpId);// scrollTo(mCurrentIndex * getWidth(), 0);moveTo();break;default:break;}return true;}private void moveTo() {int distance = mCurrentIndex * getWidth() - getScrollX();mDistanceHelper.startScroll(getScrollX(), 0, distance, 0);invalidate();}@Overridepublic boolean onDown(MotionEvent e) {if (DEBUG)Log.i(TAG, "onDown");mDownX = e.getX();return false;}@Overridepublic void onShowPress(MotionEvent e) {if (DEBUG)Log.i(TAG, "onShowPress");}@Overridepublic boolean onSingleTapUp(MotionEvent e) {if (DEBUG)Log.i(TAG, "onSingleTapUp");return false;}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {if (DEBUG)Log.i(TAG, "onScroll");// Log.i(TAG, "onScroll=" + distanceX + "," + distanceY);scrollBy((int) distanceX, 0);return false;}public void onLongPress(MotionEvent e) {if (DEBUG)Log.i(TAG, "onLongPress");}public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {if (DEBUG)Log.i(TAG, "onFling");Log.i("Gmw", velocityX + "");return false;}public void scrollNext() {}public void scrollLast() {}public void setCurrent(int index) {mCurrentIndex = index;scrollTo(index * getWidth(), 0);invalidate();// requestLayout();}public int getCurrent() {return mCurrentIndex;}@Overridepublic void computeScroll() {Log.i("Gmw", "computeScroll");if (!mDistanceHelper.computeScrollOffset()) {int newX = (int) mDistanceHelper.getCurrentX();scrollTo(newX, 0);invalidate();}// super.computeScroll();}}

距离计算帮助类 DistanceHelper
public class DistanceHelper {private int startX;private int startY;private int distanceX;private int distanceY;private long startTime;private boolean isFinish;private long duration;private long currentX;private long currentY;public long getCurrentX() {return currentX;}public void setCurrentX(long currentX) {this.currentX = currentX;}public DistanceHelper(Context context) {isFinish = false;}public void startScroll(int startX, int startY, int distanceX, int distanceY) {this.startX = startX;this.startY = startY;this.distanceX = distanceX;this.distanceY = distanceY;this.startTime = SystemClock.uptimeMillis();this.duration = 200;this.isFinish = false;}public boolean computeScrollOffset() {if (isFinish) {return isFinish;}long passTime = SystemClock.uptimeMillis() - startTime;if (passTime < duration) {currentX = startX + distanceX * passTime / duration;currentY = startY + distanceX * passTime / duration;} else {currentX = startX + distanceX;currentY = startY + distanceY;isFinish = true;}return false;}}

使用
XML文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <com.zoe.pagedview.PagedView        android:id="@+id/pagedview1"        android:layout_width="match_parent"        android:layout_height="match_parent" >    </com.zoe.pagedview.PagedView></RelativeLayout>
java代码:
public class MainActivity extends Activity {PagedView mPagedView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mPagedView = (PagedView) findViewById(R.id.pagedview1);View view;for (int i = 0; i < 5; i++) {view = new View(this);if (i == 0) {view.setBackgroundColor(Color.RED);} else if (i == 1) {view.setBackgroundColor(Color.BLUE);} else if (i == 21) {view.setBackgroundColor(Color.GREEN);} else if (i == 3) {view.setBackgroundColor(Color.YELLOW);} else if (i == 4) {view.setBackgroundColor(Color.RED);}mPagedView.addView(view);}mPagedView.setCurrent(1);}}

效果如下:



0 0
原创粉丝点击