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. idea中无法自动提示相关jar包

    遇到的问题:今天在pom.xml导入数据库坐标后,发现在在配置数据相关属性时,idea无法使用我引入的jar包,后面才发现是因为在下载包时,没网络了,jar包下载失败 解决办法:cmd进入自己的mav ...

  2. Phoenix批量提交优化,官网的demo

    1 Phoenix的批量insert官网代码,最佳实践 try (Connection conn = DriverManager.getConnection(url)) { conn.setAutoC ...

  3. 《python解释器源码剖析》第9章--python虚拟机框架

    9.0 序 下面我们就来剖析python运行字节码的原理,我们知道python虚拟机是python的核心,在源代码被编译成字节码序列之后,就将有python的虚拟机接手整个工作.python虚拟机会从 ...

  4. Oracle【序列、索引、视图、分页】

    1.Oracle序列语法:create sequence 序列名 特点1:默认是无值,指针指向没有值的位置 特点2:序列名.nextval 每次执行值会自增一次,步长为 1 特点3:序列名.currv ...

  5. fragment事务 的基本处理

    处理fragment事务 动态加载fragmentMyFragment2 fragment2=new MyFragment2();//new出一个fragment对象FragmentManager f ...

  6. 8.Netty发送对象

    1.Netty发送对象简介: Netty中,通讯的双方建立连接后,会把数据按照ByteBuf的方式进行传输,例如http协议中,就是通过HttpRequestDecoder对 ByteBuf数 据流进 ...

  7. 检测udp端口

    linux 检测端口是否打开:nc -zuv ip 端口 服务器监听端口:nc -l -u ip 端口(可以发送和接受信息) 客户端检测端口:nc -u ip 端口(可以发送和接受信息) 查看监听的t ...

  8. sql 新增一个不为空的列

    ALTER TABLE dbo.FW_PATROL_TASK ADD CRUISE_TYPE INT; UPDATE FW_PATROL_TASKSET CRUISE_TYPE = 0; --设置新列 ...

  9. Ubuntu18.04系统执行语句时出现错误Failed to load module "canberra-gtk-module"

    Ubuntu18.04系统执行gnuradio-companion时,命令行提示错误Failed to load module "canberra-gtk-module",虽然看起 ...

  10. USRPX310 在GNU Radio上更改通道A或B

    UHD:USRP sink和USRP source默认是A通道发射接收.或设置 Mb0:Subdev Spec: A:0 更改为B通道收发:设置 Mb0:Subdev Spec: B:0