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. yolo模型的特点与各版本性能对比

    目录 一.YOLOV1 二.YOLOV2 二.YOLOV3 正文 目前,基于深度学习的目标检测算法大致可以分为两大流派: 1.两阶段(two-stage)算法:先产生候选区域然后再进行CNN分类(RC ...

  2. vue中 localStorage的使用方法(详解)

    vue中实现本地储存的方法:localStorage,在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie存储空间不足的问题(cooki ...

  3. IPC之msg.c源码解读

    // SPDX-License-Identifier: GPL-2.0 /* * linux/ipc/msg.c * Copyright (C) 1992 Krishna Balasubramania ...

  4. java中有个很强大的工具jconsole.exe

    这个工具可以监控java程序的线程,cpu和内存使用情况.

  5. ubuntu配置jdk(收藏)

    ubuntu下JDK配置本质上和win是一样的: 1.去官网下载JDK7,找jdk-7u21-linux-i586.tar.gz并下载:http://www.oracle.com/technetwor ...

  6. HelloWorld编写过程中注意事项

    一.package关键字 * package表示当前代码所属的包(package),是一种组织结构.其他package通过包名调用这个包下内容* package是必须的,每个文件的package必须存 ...

  7. 第七章 路由 76 路由传参-使用params方式传递路由参数

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

  8. Centos7网卡配置命令nmcli

    在配置Centos6时,大家第一想到的就是把networkManager这个服务关掉,让它消失,这个服务台太鸡肋了,不该起作用的时候经常起作用,给管理带来了不便,但是在Centos7当中network ...

  9. 【模板】多标记 LCT

    代码如下 #include <bits/stdc++.h> using namespace std; typedef long long LL; const int mod = 51061 ...

  10. CSS引入外部字体方法,附可用demo

    有时候我们做的页面需要用到一些更好看的字体又不想用图片代替,图片会影响加载速度则使用外部字体来显示但是直接通过font-family又不一定全部都行这就需要我们在css中进行定义并且引入字体文件路径然 ...