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>

效果:

自定义ViewPager+RadioGroup联动效果的实现的更多相关文章

  1. 实现ViewPager的联动效果

    参考链接:android - Synchronizing two ViewPagers using OnPageChangeListener - Stack Overflow 其中有个非常完美的解决方 ...

  2. Android 自定义 ViewPager 打造千变万化的图片切换效果

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38026503 记得第一次见到ViewPager这个控件,瞬间爱不释手,做东西的主 ...

  3. Android实现图片轮显效果——自定义ViewPager控件

    一.问题概述 使用ViewPager控件实现可横向翻页.水平切换图片等效果,但ViewPager需要手动滑动才能切换页面,图片轮显效果的效果本质上就是在ViewPager控件的基础上让它能自动的进行切 ...

  4. jquery.cityselect.js基于jQuery+JSON的省市或自定义联动效果

    一.插件介绍 最早做省市联动的时候都特别麻烦,后来在helloweba的一篇文章中看到这个插件,很不错的,后来就一直用了. 省市区联动下拉效果在WEB中应用非常广泛,尤其在一些会员信息系统.电商网站最 ...

  5. Android底部导航栏创建——ViewPager + RadioGroup

    原创文章,引用请注明出处:http://www.cnblogs.com/baipengzhan/p/6270201.html Android底部导航栏有多种实现方式,本文详解其中的ViewPager ...

  6. Android之自定义ViewPager实现图片的无线轮播

    PS:以前也写过关于图片轮播这一块的博客.不过写的很烂,并且很多情况没有考虑到(没有支持无线轮播,和手势点击事件).因此这里写一篇补上.也是当时太年轻了. 注:图片请放大后再看.否则看不清楚. 学习内 ...

  7. Json 基于jQuery+JSON的省市联动效果

    helloweba.com 作者:月光光 时间:2012-09-12 21:57 标签: jQuery  JSON  Ajax  省市联动     省市区联动下拉效果在WEB中应用非常广泛,尤其在一些 ...

  8. 【转】android 自定义ViewPager,修改原动画

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38026503 记 得第一次见到ViewPager这个控件,瞬间爱不释手,做东西的 ...

  9. 仿百度壁纸客户端(二)——主页自定义ViewPager广告定时轮播图

    仿百度壁纸客户端(二)--主页自定义ViewPager广告定时轮播图 百度壁纸系列 仿百度壁纸客户端(一)--主框架搭建,自定义Tab + ViewPager + Fragment 仿百度壁纸客户端( ...

随机推荐

  1. kali工具的总结

    由于篇幅有限,只列举部分,ps:第一次发有什么不对的 还望各位大大指正 nc 瑞士军刀 [v1.10-41] 使用格式: nc [-参数] 主机名 端口[s] [端口] … 侦听入站: nc -l - ...

  2. 【2017-05-19】WebForm复合控件、用DropDownList实现时间日期选择。

    自动提交的属性: AutoPostBack="True" 1.RadioButtonList     单选集合 -属性:RepeatDirection:Vertical (垂直排布 ...

  3. MFC的一些常用操作

    一.添加消息 MFC和win32不同的一点是MFC采用的是消息的映射机制,即每一个消息都和处理的函数做了映射,我们可以通过查找的方式来得到消息的对应的函数,当然MFC提供了一个非常简便的方法,我们通过 ...

  4. shell基本概念

    一.shell分类 常见shell:bash.zsh.tcsh linux默认:bash shell #tcsh #bash #pstree | grep login |- .. .. |-login ...

  5. 8.4.Zookeeper结构和命令

    1. Zookeeper结构 1.1.ZooKeeper数据模型Znode ZooKeeper拥有一个层次化的目录结构,命名符合常规文件系统规范 ZooKeeper树中的每个节点被称为—Znode,和 ...

  6. 安装docker fastdfs

    # step 1: 安装必要的一些系统工具 sudo yum install -y yum-utils device-mapper-persistent-data lvm2# Step 2: 添加软件 ...

  7. jdk提供的线程协调API suspend/resume wait/notify park/unpark

    线程通信(如 线程执行先后顺序,获取某个线程执行的结果等)有多种方式: 文件共享 线程1 --写入--> 文件 < --读取-- 线程2 网络共享 变量共享 线程1 --写入--> ...

  8. 第七章 路由 77 路由-使用children属性实现路由嵌套

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  9. Resource ResourceLoader

    DefaultResourceLoader   -- > ResourceLoader 方法 ResourceLoader getResource(String location); Class ...

  10. Python学习笔记:序列构成的数组

    列表推导是一种构建列表(list)的快捷方式 #列表推导 symbols = '!@#$%' codes = [ord(symbol) for symbol in symbols] #ord()Pyt ...