android自定义控件-AutoScrollViewpager(无限滚动轮播控件)

在实现该控件之前,先说一下该控件的难度,

一、

  每个item中如果有RadioButton之类,可以focus焦点的,点击效果可能会失效 

 二、无限的滚动

  下面是效果图:


实现上图的效果,一共自定义了两个 控件,viewpager+底部导航图标

下面我先来讲解一下,viewpager的实现:

1.初始化

<pre name="code" class="java">/** 点击按下的坐标 **/
	PointF downP = new PointF();
	/** 当前按下的坐标 **/
	PointF curP = new PointF();
	OnSingleTouchListener onSingleTouchListener;
	public MyPagerAdapter adapter;
	public ArrayList<View> listViews;
	private Activity acitvity;
	private boolean isTouch = false;
	AutoScrollViewPager viewpager;
	AutoScrollViewPagerStateChange stateChange;


public AutoScrollViewPager(Context context, AttributeSet attrs) {
		super(context, attrs);
		listViews = new ArrayList<View>();
		viewpager = this;
		adapter = new MyPagerAdapter();
		viewpager.setAdapter(adapter);
		initOntouch();
	}<pre code_snippet_id="1780518" snippet_file_name="blog_20160723_3_7858134" name="code" class="java"><pre code_snippet_id="1780518" snippet_file_name="blog_20160723_2_1968790" name="code" class="java"><pre code_snippet_id="1780518" snippet_file_name="blog_20160723_3_7858134" name="code" class="java">listViews 存放轮播所需的图片
adapter是  viewpager的pageradapter
initOntouch()方法是设置touch事件的监听实现点击,获取当前点击的下标
通过对比touch中 down和up的点的x,y的值是否相同,相同表示点击,不同不做处理



private void initOntouch() {
		// TODO Auto-generated method stub
		viewpager.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View arg1, MotionEvent arg0) {
				// TODO Auto-generated method stub
				// 给当前坐标赋值
				curP.x = arg0.getX();
				curP.y = arg0.getY();

				if (arg0.getAction() == MotionEvent.ACTION_DOWN) {
					//
					// 给当前按下赋值
					downP.x = arg0.getX();
					downP.y = arg0.getY();
					// 设置 获取当前事件,通知父控件不将事件在进行分发
					getParent().requestDisallowInterceptTouchEvent(true);
					isTouch = true;
				}

				if (arg0.getAction() == MotionEvent.ACTION_MOVE) {
					//
					getParent().requestDisallowInterceptTouchEvent(true);
					isTouch = true;
				}

				if (arg0.getAction() == MotionEvent.ACTION_UP) {
					//
					//判断是否是点击操作
					<span>if (downP.x == curP.x && downP.y == curP.y) {
						onSingleTouch(viewpager.getCurrentItem()
								% listViews.size());
					}</span>
					isTouch = false;

				} else if (arg0.getAction() == MotionEvent.ACTION_CANCEL) {
					getParent().requestDisallowInterceptTouchEvent(false);

				}

				return false;
			}
		});
	}<pre name="code" class="java"><span>	</span>/**
	 * 单击事件
	 */
	public void onSingleTouch(Object obj) {
		if (onSingleTouchListener != null) {
			onSingleTouchListener.onSingleTouch(obj);
		}
	}

	/**
	 * 单机事件接口
	 */
	public interface OnSingleTouchListener {
		public void onSingleTouch(Object obj);
	}


</pre><pre code_snippet_id="1780518" snippet_file_name="blog_20160723_10_5295814" name="code" class="java">getParent().requestDisallowInterceptTouchEvent(false);该方法是通知父控件是否还要继续分发事件,true表示阻止父控件继续分发,false表示不做限制
<span>isTouch 表示再定時器中做处理</span>
2.无限轮播的原理 
<span>  原理: 假设  一共有  4张图片,当viewpager滚动到第4张得时候,图片直接显示第一张,所以在 viewpager的adapter中就要做如下处理</span>
// viewpager的 adapter
	private class MyPagerAdapter extends PagerAdapter {

		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			// return listViews.size();
			return Integer.MAX_VALUE;
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			// TODO Auto-generated method stub
			return arg0 == arg1;
		}

		public void destroyItem(ViewGroup container, int position, Object object) {
			container.removeView(listViews.get(position % listViews.size()));// 删除上个图片
		}

		public Object instantiateItem(ViewGroup container, int position) {
			container.addView(listViews.get(position % listViews.size()), 0);//
			return listViews.get(position % listViews.size());
		}
	}
其中 设置 让 getCount返回一个 最大值,这样在用户浏览的时候,看起来是一直在做无限轮播,(ps:如果用户如果有足够的耐心等待,图片真正的轮播完全的时候,图片就会停留到  listViews.get(Integer.MAX_VALUE % listViews.size())的那张图片,不过得很长时间)

<span>3.定时器</span>
<span></span><pre name="code" class="java">	/**
	 * 定时器
	 */
	private Timer time;
	boolean isScroll = false;

	public void startScroll() {
		if (isScroll)
			return;

		if (time == null)
			time = new Timer();
		time.schedule(new TimerTask() {

			@Override
			public void run() {
				isScroll = true;
				Runnable run = new Runnable() {
					@Override
					public void run() {
						// TODO Auto-generated method stub

						if (<span>isTouch</span>) {//isTouch是在touch监听接口中赋值,来监听是否是用户正在触摸屏幕,如果是将会不做任何处理,也就实现了,解决了当用户想要手动查看轮播的内容时,会自动换掉当前图片

						} else {
							int current = viewpager.getCurrentItem();

							if (current < adapter.getCount() - 1) {
								viewpager.setCurrentItem(current + 1);
							} else {
								viewpager.setCurrentItem(0);
							}
						}
					}

				};

				viewpager.post(run);//UI的操作都要在主线程中,所以 用viewpager  post方法来更改UI,否则会报错
			}

		}, 500, 2000);

	}
public void stopScroll() {
		if (time != null) {
			time.cancel();
			time = null;
		}
	}

其中 startScroll()方法是在Activity或者 Fragment中初始化之后,调用的


<span>3、底部指示器的绘制</span>
<pre name="code" class="java"> 
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
/**
 * viewpager 底部下标指示器
 * @author ML  2015-05-29
 *
 */
public class AutoScrollViewPagerStateChange extends View {
	public AutoScrollViewPagerStateChange(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	private int size, current;

	@SuppressLint("NewApi")
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		Paint p = new Paint();
		p.setAntiAlias(true);
		p.setAlpha(1);
 		int item_width = 30;
 		int item_height=5;
 		int jiange=20;
		int center_x = (getWidth() - item_width * size-jiange*(size)) / 2;
        int lastright = 0;
 		for (int i = 0; i < size; i++) {
			p.setColor(Color.parseColor("#ff00ff"));//表示不是当前页面的颜色
			p.setStyle(Style.FILL);
			if (i == current) {
				p.setStyle(Style.FILL);
				p.setColor(Color.WHITE);<span>//表示 当前页面的颜色</span>

			}
<span>			/*canvas.drawCircle(center_x + item_width / 2 + i * item_width,</span><span>getHeight() / 2, 10, p);*/
</span><span>	int left=center_x + item_width / 2 + i * item_width</span><span>	
	if(i!=0)left=lastright+jiange;
</span><pre code_snippet_id="1780518" snippet_file_name="blog_20160723_24_8667830" name="code" class="java">	int right=left+item_width;
              lastright=right;

  			int top=0;
			int bottom=item_height;
 			Rect r=new Rect(left,top,right,bottom);
			canvas.drawRect(r, p);
		
			
			
 		}
		canvas.save();
 	}

	public void drawCicle(int size, int current) {
		this.size = size;
		this.current = current;
		invalidate();
	}
}

<span>指示器是通过  canvas paint 来绘制的 通过计算 每一个  长方形的  起始位置  来动态的  改变指示器,在当前下标的 长方形哪里改变一下  paint的颜色值,就可以实现底部切换的效果</span>
如有错误,欢迎指正
源代码:稍后上传到github上 ,









本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。

Android-下拉刷新库 - 2016-07-24 14:07:44

前言 入职接近半个多月,有几天空闲,所以想着能不能自己实现一个库来练练手,因为之前一直想要实现下拉刷新的功能,因此就有了这样一个自制的下拉刷新库——RefreshWidgetLib. 关于下拉刷新 下拉刷新,作为一个几乎每个应用都会出现的一种控件,不言而喻,它对于提高用户体验有着很重要的作用,而且也已经成为了人们习惯的一种操作。说起下拉刷新这种设计,最早的引入者是在2008年上线的Tweetie,Tweetie引入了如今随处可见的“下拉刷新”设计,不仅有多达数百款App Store应用使用这种设计,就连苹

从AIDL看Android跨进程通信 - 2016-07-24 14:07:38

AIDL是Android实现IPC的一种重要的方式,理解它的原理对理解Android进程间通信有很大的帮助。AIDL的定义,已经有很多介绍的文章了,这里就不做详解了。我们直接从实例入手来分析AIDL实现原理。 AIDL的使用 首先需要定义AIDL接口IMyService.aidl: // IMyService.aidl package com.chuck.aidldemo; // Declare any non-default types here with import statements inter
OC与Swift两种实现方式基本上区别不大,主要是在一些对象或方法的调用方式不同 OC代码样式: self.view.backgroundColor = [UIColor blackColor];          //加载颗粒状的火花图片     CAEmitterLayer *emitterLa = [CAEmitterLayer layer];     emitterLa.emitterPosition = CGPointMake(self.view.bounds.size.width/2, sel
前言 相信很多朋友在开发中都会遇到图片上传的情况,尤其是多图上传,最 经典的莫过于微信的图片选择了。所有很多情况下会使用到多图选择。 所以就有了这篇文章,今天抽点时间写了个控件。 支持自定义选择图片的样式 支持设置图片选择数量 支持图片预览,删除 支持图片拍照 先来看看效果 实现分析 假如不定义控件,我们要实现这样一个功能,无非是写个GridView在item点击的时候去显示图片进行选择,在返回界面的时候进行GridView的数据刷新。我们把这些逻辑写在我们自定义的GridView中,就成了一个新的控件。
在360对DroidPlugin的特点介绍中有云: 插件的四大组件完全不需要在Host程序中注册,支持Service、Activity、BroadcastReceiver、ContentProvider四大组件。 实现了进程管理,插件的空进程会被及时回收,占用内存低。 之所以支持Service,Activity,ContentProvider三大组件,是因为DroidPlugin在AndroidManifest文件中预先注册了8个运行插件的进程,每个进程预注册Service一个, ContentProvi
本篇介绍ListView控件,这是Android中比较重要也比较复杂的控件,这里只谈到使用ViewHolder机制优化即可。 一、ListView简介 ListView是Android系统中显示列表的控件,每个ListView都可以包含很多个列表项。 二、ListView的使用 概念不多说,直接来介绍使用方法。 ListView中比较复杂的是数据适配器,其作用是把复杂的数据(数组、链表、数据库、集合等)填充在指定视图界面,是连接数据源和视图界面的桥梁。常见的Android原生的适配器有ArrayAdapt
欢迎转载,转载请注明出处: http://blog.csdn.net/dmk877/article/details/51912104   相信不管做了多长时间开发的人都用过Tween动画,从刚开始工作到现在我也是用了N次Tween动画,但是每一次使用总感觉掌握的不够全面,所以花了点时间详细的总结了下Tween动画,其实在android中熟练掌握动画,能够帮助我们实现一些非常酷炫的效果从而使我们的app在交互或者用户体验上有一个更好的体验,鉴于此详细的学习动画还是很有必要的,相信通过本篇的学习大家会对Twe

Java(Android)回调函数详解 - 2016-07-23 17:07:29

一、前言 本周有位入行开发不久的朋友问我回调究竟是个什么概念,在网上看了很多的回调函数解释,但是越看越乱。虽然回调函数这个梗已经不新鲜了,这里还是用书面的形式记录下。 如果有了解的,就无需再看。 二、概念 概念上,这里引用百度百科的解释,如下: 回调函数就是一个通过 函数指针 调用的函数。如果你把函数的 指针 (地址)作为 参数传递 给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或

Android_聊天_表情 - 2016-07-23 17:07:26

接下来就进入聊天界面了,我的界面效果如下几个图所示: 这其中包括两个点:仿微信按住说话功能,表情管理 第一个,按住说话 按钮的功能,通过重写Button完成, /** * 控制录音Button * 1、重写onTouchEvent;(changeState方法、wantToCancel方法、reset方法); * 2、编写AudioDialogManage、并与该类AudioRecorderButton进行整合; * 3、编写AudioManage、并与该类AudioRecorderButton进行整合;

JAVA 面向对象 隐藏和封装 - 2016-07-23 17:07:20

本页面更新日期: 2016年07月22日 前言 在前面程序中,经常出现通过 某个对象直接访问其成员变量的情况. 这可能引起一些潜在问题,比如将某个 Person 的 age 成员变量直接设为 1000. 这在语法上没有任何问题, 但显然违背了当前的自然规律. 人怎么可能活到 1000岁 - - . (就现在的科学来讲) Java也考虑到了这种情况, 为你提供了 类和对象的成员变量 进行封装的方法,来保护成员变量不被恶意修改. 理解封装 封装(Encapsulation) 是面向对象的三大特征之一.(另外两