package com.loaderman.myviewpager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class MainActivity extends AppCompatActivity {
private MyViewPager mViewPager;
private RadioGroup rgGroup;
private int[] mImageIds = new int[]{R.drawable.a1, R.drawable.a2, R.drawable.a3, R.drawable
.a4, R.drawable.a5, R.drawable.a6};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (MyViewPager) findViewById(R.id.viewpager);
rgGroup = (RadioGroup) findViewById(R.id.rg_group);
//给自定义Viewpager添加图片
for (int id : mImageIds) {
ImageView view = new ImageView(this);
view.setBackgroundResource(id);
mViewPager.addView(view);
}
//添加测试页面布局
View view = View.inflate(this, R.layout.item_test, null);
mViewPager.addView(view, 2);
//动态添加RaidoButton
for (int i = 0; i <= mImageIds.length; i++) {
RadioButton rb = new RadioButton(this);
rb.setId(i);//以当前位置为id
rgGroup.addView(rb);
if (i == 0) {
rb.setChecked(true);
}
}
//点击RadioButton, 切换页面
rgGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
System.out.println("checkedId:" + checkedId);
int pos = checkedId;
mViewPager.setCurrentItem(pos);
}
});
//切换页面, 更新RadioButton
mViewPager.addOnPageChangeListener(new MyViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
int id = position;
rgGroup.check(id);
}
}); }
}
package com.loaderman.myviewpager;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
* 自定义ViewPager流程:
* 1. 写一个类继承ViewGroup
* 2. 在actvity中添加图片对象
* 3. 重写onLayout, 保证子控件一字排开
* 4. 滑动布局,切换页面, 手势识别器 onScroll: scrollBy, scrollTo
* 5. 平滑滑动效果 Scroller滑动器
* 6. 加测试页面ScrollView
* 7. 重写onMeasure测量所有子控件
* 8. 事件传递流程, 苹果例子
* 9. 事件拦截流程
* 10. 保证viewpager和scrollview分别处理相关事件
* 11. 添加RadioButton
* 12. 点击RadioButton切换页面
* 13. 滑动页面, 切换RadioButton
*/
public class MyViewPager extends ViewGroup {
private GestureDetector mDetector;
private Scroller mScroller;
private int startX;
private int startY;
public MyViewPager(Context context) {
this(context, null);
}
public MyViewPager(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public MyViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mDetector = new GestureDetector(getContext(), new GestureDetector
.SimpleOnGestureListener() {
//触摸滑动的方法
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float
distanceY) {
//distanceX: 水平滑动距离
scrollBy((int) distanceX, 0);//基于当前位置进行滑动, 参1:水平滑动的偏移量, 相对位置
return super.onScroll(e1, e2, distanceX, distanceY);
}
});
//滑动器
mScroller = new Scroller(getContext());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);//设置ViewPager本身的尺寸
//遍历所有子控件,设置每个控件的尺寸
//解决测试页面显示白板的问题
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, heightMeasureSpec);
}
//widthMeasureSpec: 并不是真实的宽高信息, 它包含两部分, 1: 宽高模式信息; 2. 具体的尺寸
// System.out.println("widthMeasureSpec:" + widthMeasureSpec);
// System.out.println("heightMeasureSpec:" + heightMeasureSpec);
//MeasureSpec.AT_MOST; 至多模式, 当前控件有多大就显示多大 wrap_content
//MeasureSpec.EXACTLY; 确定模式, 宽高写死dp, match_parent(父控件多大,我就多大,所以也是确定的)
//MeasureSpec.UNSPECIFIED; 未确定模式, ListView, ScrollView // int mode = MeasureSpec.getMode(widthMeasureSpec);
// int size = MeasureSpec.getSize(widthMeasureSpec);
//
// System.out.println("mode:" + mode);
// System.out.println("size:" + size);
}
//设置控件的位置
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//遍历所有子控件, 设置每个子控件位置
//子控件一字排开
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.layout(getWidth() * i, 0, getWidth() * (i + 1), getHeight());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("ViewPager 按下...");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("ViewPager 移动...");
break;
case MotionEvent.ACTION_UP:
System.out.println("ViewPager 抬起...");
//手指抬起
//确定下一页的位置
int scrollX = getScrollX();//获取当前移动后的x值
// System.out.println("scrollX:" + scrollX);
//计算当前页面位置
int currPos = scrollX / getWidth();
// System.out.println("currPos:" + currPos);
int offset = scrollX % getWidth();//多划出的距离
if (offset > getWidth() / 2) {
currPos++;
}
//避免越界 0->图片个数-1
if (currPos < 0) {
currPos = 0;
}
if (currPos > getChildCount() - 1) {
currPos = getChildCount() - 1; //System.out.println("下一页位置:" + currPos); //跳到下一页位置
// scrollTo(currPos * getWidth(), 0);//绝对位置,移动到确定位置
//计算滑动距离
// int dx = currPos * getWidth() - getScrollX();//目标位置-当前位置=滑动距离
// //此方法不能产生滑动的动画效果, 会导致回调computeScroll方法, 需要在computeScroll方法中处理动画
// mScroller.startScroll(getScrollX(), 0, dx, 0, Math.abs(dx));//距离和时间要成正比
// invalidate();//要刷新界面
setCurrentItem(currPos);
break;
default:
break;
}
return true;
}
//此方法会回调多次, 每一次回调后修改页面位置, 连续在一起就形成动画
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {//判断有没有滑动结束
int currX = mScroller.getCurrX();//获取当前应该滑动到的位置
System.out.println("currX:" + currX);
scrollTo(currX, 0);//滑动到特定位置
invalidate();//要刷新界面
}
}
//事件分发
//dispatchTouchEvent->onInterceptTouchEvent-->onTouchEvent
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//如果上下滑动, 不需要中断事件
//左右滑动, 才需要中断事件
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) ev.getX();
startY = (int) ev.getY();
//由于按下之后, 返回false, 按下事件被子控件处理,导致ViewPager丢掉了按下事件,滑动时页面出现bug
//补上按下事件
mDetector.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
int endX = (int) ev.getX();
int endY = (int) ev.getY();
int dx = endX - startX;
int dy = endY - startY;
if (Math.abs(dx) > Math.abs(dy)) {
//左右滑动
return true;//表示中断事件传递, 交给当前ViewPager处理, 子控件无法处理
}
break;
default:
break;
}
return false;//不中断事件, 交给子控件(ScrollView)处理
}
//设置当前页面
public void setCurrentItem(int pos) {
//计算滑动距离
int dx = pos * getWidth() - getScrollX();//目标位置-当前位置=滑动距离
//此方法不能产生滑动的动画效果, 会导致回调computeScroll方法, 需要在computeScroll方法中处理动画
mScroller.startScroll(getScrollX(), 0, dx, 0, Math.abs(dx));//距离和时间要成正比
invalidate();//要刷新界面
//回调页面位置
if (listener != null) {
listener.onPageSelected(pos);
}
}
private OnPageChangeListener listener;
public void addOnPageChangeListener(OnPageChangeListener listener) {
this.listener = listener;
}
public interface OnPageChangeListener {
public void onPageSelected(int position);
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.loaderman.myviewpager.MainActivity"> <RadioGroup
android:id="@+id/rg_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
</RadioGroup> <com.loaderman.myviewpager.MyViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>

item_test.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--item_test-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试文本"
android:textSize="30sp"/>
</LinearLayout>
</ScrollView>

效果:

最新文章

  1. mysql 内连接、左连接、右连接
  2. 前端学PHP之面向对象系列第六篇——简单图形面积计算器实现
  3. selenium截图对比校验方法
  4. iOS app性能优化的那些事
  5. 用Python抓网页的注意事项
  6. oop实现方法与属性继承
  7. UVA 10163 Storage Keepers(dp + 背包)
  8. js中从blob提取二进制
  9. Work 1(导游类)(2017.06.27)
  10. Accounting Flexfield Setup and Usage (Doc ID 124333.1)
  11. 双字节验证:vue输入框中英文字数长度验证
  12. 处理数据库 Ora-00845: memory_traget not supported on this system 的错误
  13. 在 golang 中使用 Json
  14. python - wmi模块学习(windwos硬件信息获取)
  15. Linux组管理和权限管理
  16. 1、CentOS部署Java开发环境
  17. 图片Bitmap在本地的存储与读取 File
  18. 2018/6/29 关于hashmap的总结
  19. Global.asax的Application_BeginRequest实现url重写无后缀的代码
  20. convert CAN frame

热门文章

  1. Win10带有网络连接的安全模式怎么开启?
  2. Mysql(四)-1:单表查询
  3. 22_7mybaits注解开发
  4. D - Beautiful Graph CodeForces - 1093D (二分图染色+方案数)
  5. 集成 jpush
  6. 如何阻止&lt;a&gt;标签默认行为和表单提交
  7. Maven 安装 与 使用
  8. nodejs基础一
  9. spark写数据入kafka示范代码
  10. Python之threading模块的使用