`
onewayonelife
  • 浏览: 259738 次
  • 性别: Icon_minigender_1
  • 来自: 太原
社区版块
存档分类
最新评论

Android 自定义滚动视图

 
阅读更多

MainActivity

package org.wp.activity;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;

public class MainActivity extends Activity {
	private ImageScrollView imageScrollView = null;
	private PageControlView pageControlView = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		imageScrollView = (ImageScrollView) this.findViewById(R.id.myImageScrollView);

		ImageView imageView = new ImageView(this);
		imageView.setImageResource(R.drawable.a1);
		imageScrollView.addView(imageView);

		imageView = new ImageView(this);
		imageView.setImageResource(R.drawable.a2);
		imageScrollView.addView(imageView);

		imageView = new ImageView(this);
		imageView.setImageResource(R.drawable.a3);
		imageScrollView.addView(imageView);

		imageView = new ImageView(this);
		imageView.setImageResource(R.drawable.a4);
		imageScrollView.addView(imageView);

		imageView = new ImageView(this);
		imageView.setImageResource(R.drawable.a5);
		imageScrollView.addView(imageView);

		imageView = new ImageView(this);
		imageView.setImageResource(R.drawable.a6);
		imageScrollView.addView(imageView);

		pageControlView = (PageControlView) this.findViewById(R.id.myPageControlView);
		/** 设置圆圈的数量 **/
		pageControlView.setCount(imageScrollView.getChildCount());
		/** 初始化圆圈 **/
		pageControlView.generatePageControl(0);
		/** 设置视图切换回调函数实现 **/
		imageScrollView.setScrollToScreenCallback(pageControlView);
	}
}

 

ImageScrollView

package org.wp.activity;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

public class ImageScrollView extends ViewGroup {
	/** 滚动对象Scroller **/
	private Scroller scroller = null;
	/** 手势识别对象GestureDetector **/
	private GestureDetector gestureDetector = null;
	/** 当前屏幕索引 **/
	private int currentScreenIndex = 0;
	/** 设置一个标志位,防止底层的onTouch事件重复处理UP事件 **/
	private boolean fling = false;

	public ImageScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView(context);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		/** 设置布局,将子视图顺序横屏排列 **/
		for (int i = 0; i < getChildCount(); i++) {
			View child = getChildAt(i);
			child.setVisibility(View.VISIBLE);
			child.measure(right - left, bottom - top);
			child.layout(i * getWidth(), 0, (i + 1) * getWidth(), getHeight());
		}
	}

	/** 初始化 **/
	private void initView(final Context context) {
		this.scroller = new Scroller(context);

		this.gestureDetector = new GestureDetector(new OnGestureListener() {
			@Override
			public boolean onSingleTapUp(MotionEvent e) {
				return false;
			}

			@Override
			public void onShowPress(MotionEvent e) {
			}

			@Override
			public boolean onScroll(MotionEvent e1, MotionEvent e2,
					float distanceX, float distanceY) {
				// 防止移动过最后一页
				if ((distanceX > 0 && getScrollX() < getWidth() * (getChildCount() - 1))
						|| (distanceX < 0 && getScrollX() > 0)) {// 防止向第一页之前移动
					scrollBy((int) distanceX, 0);
				}
				return true;
			}

			@Override
			public void onLongPress(MotionEvent e) {
			}

			@Override
			public boolean onFling(MotionEvent e1, MotionEvent e2,
					float velocityX, float velocityY) {
				// 判断是否达到最小轻松速度,取绝对值的
				if (Math.abs(velocityX) > ViewConfiguration.get(context)
						.getScaledMinimumFlingVelocity()) {
					if (velocityX > 0 && currentScreenIndex > 0) {
						fling = true;
						scrollToScreen(currentScreenIndex - 1);
					} else if (velocityX < 0 && currentScreenIndex < getChildCount() - 1) {
						fling = true;
						scrollToScreen(currentScreenIndex + 1);
					}
				}
				return true;
			}

			@Override
			public boolean onDown(MotionEvent e) {
				return false;
			}
		});
	}

	/** 切换到指定屏 **/
	public void scrollToScreen(int whichScreen) {
		if (whichScreen != currentScreenIndex && getFocusedChild() != null
				&& getFocusedChild() == getChildAt(currentScreenIndex)) {
			getFocusedChild().clearFocus(); // 清除焦点
		}

		final int delta = whichScreen * getWidth() - getScrollX();
		scroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);
		invalidate();

		currentScreenIndex = whichScreen; // 设置当前屏幕索引
		if (scrollToScreenCallback != null) { // 刷新圆圈
			scrollToScreenCallback.callback(currentScreenIndex);
		}
	}

	@Override
	public void computeScroll() {
		// 当滚动没有完成
		if (scroller.computeScrollOffset()) {
			scrollTo(scroller.getCurrX(), 0);
			postInvalidate();
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		gestureDetector.onTouchEvent(event);

		if (event.getAction() == MotionEvent.ACTION_UP) {
			if (!fling) {
				// 当用户停止拖动
				snapToDestination();
			}
			fling = false;
		}
		return true;
	}

	/** 根据当前x坐标位置确定切换到第几屏 **/
	private void snapToDestination() {
		scrollToScreen((getScrollX() + (getWidth() / 2)) / getWidth());
	}

	/** 底部圆圈显示回调接口 **/
	interface ScrollToScreenCallback {
		public void callback(int currentIndex);
	}

	/** ScrollToScreenCallback回调对象 **/
	private ScrollToScreenCallback scrollToScreenCallback;

	/** 设置回调函数对象 **/
	public void setScrollToScreenCallback(ScrollToScreenCallback scrollToScreenCallback) {
		this.scrollToScreenCallback = scrollToScreenCallback;
	}
}

 

PageControlView

package org.wp.activity;

import org.wp.activity.ImageScrollView.ScrollToScreenCallback;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class PageControlView extends LinearLayout implements
		ScrollToScreenCallback {
	/** Context对象 **/
	private Context context;
	/** 圆圈的数量 **/
	private int count;

	public PageControlView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
	}

	/** 回调函数 **/
	@Override
	public void callback(int currentIndex) {
		generatePageControl(currentIndex);
	}

	/** 设置选中圆圈 **/
	public void generatePageControl(int currentIndex) {
		this.removeAllViews();

		for (int i = 0; i < this.count; i++) {
			ImageView iv = new ImageView(context);
			if (currentIndex == i) {
				iv.setImageResource(R.drawable.page_indicator_focused);
			} else {
				iv.setImageResource(R.drawable.page_indicator);
			}
			this.addView(iv);
		}
	}

	/** 设置圆圈数量 **/
	public void setCount(int count) {
		this.count = count;
	}
}

 

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" 
	android:layout_height="fill_parent">
	<org.wp.activity.ImageScrollView android:layout_width="fill_parent"
		android:layout_height="fill_parent"
		android:id="@+id/myImageScrollView" />
	<org.wp.activity.PageControlView android:layout_width="fill_parent"
		android:layout_height="40dip"
		android:layout_alignParentBottom="true"
		android:background="#8f00000f"
		android:gravity="center"
		android:id="@+id/myPageControlView" />	
</RelativeLayout>

 

 

 

分享到:
评论
2 楼 M985300651 2012-12-05  
難得一見的好教學
1 楼 423884605 2012-03-01  
很精辟 找了好久 能给个demo吗97687283@qq.com

相关推荐

    Android自定义图文滚动控件

    "Android自定义图文滚动控件"是一个基于网上的wheelview组件进行改造的项目,它旨在实现图文结合的滚动效果,并且允许开发者根据需求进行大量自定义设置。下面我们将详细探讨这个控件的实现原理、功能特性以及如何在...

    自定义recyclerView的滚动条样式

    滚动条是系统提供的一种视觉反馈,当用户滚动视图时,它会显示出来表示内容是否可滚动以及当前滚动位置。在XML布局文件中,可以通过`android:scrollbars`属性来启用RecyclerView的滚动条,如`android:scrollbars=...

    Android自定义日期选择器源码

    博客文章“Android自定义日期选择器源码”可能详细介绍了以下关键点: 1. **自定义View组件**:创建一个新的`View`类,继承自`ViewGroup`,在这个类中,我们需要绘制日期选择器的所有元素,包括背景、网格线、日期...

    Android自定义控件实现导航条IndicatorView

    在Android应用开发中,自定义控件是提升用户体验和界面个性化的重要手段。本文将深入探讨如何实现一个自定义的...不断学习和实践,将帮助你更好地理解和掌握Android自定义控件的精髓,为你的应用带来更丰富的用户体验。

    Android-在滚动自定义NestedScrollView的同时使视图从顶部和底部隐藏的库

    其中,NestedScrollView作为Android SDK提供的一种可滚动视图,允许嵌套其他的滚动视图,使得开发者可以创建多层滚动效果。然而,有时我们希望在滚动过程中实现某些视图的动态隐藏或显示,比如在顶部或底部达到一定...

    Android自定义滚动式时间选择器(在他人基础上修改)Demo

    首先,从标题“Android自定义滚动式时间选择器(在他人基础上修改)Demo”可以看出,这个项目是一个示例程序,它是在其他开发者的工作基础上进行改进的。通常,这种改进可能包括优化性能、增强功能、调整UI设计或者...

    Android自定义SeekBar滑动条

    本篇文章将深入探讨如何在Android中自定义SeekBar,以满足更个性化的视觉效果和交互需求。 1. **自定义SeekBar的基本步骤** - 创建一个新的XML布局文件,在其中定义SeekBar,可以设置基本属性如id、width、height...

    android 滚动视图效果源码.zip

    本资源“android 滚动视图效果源码.zip”提供了自定义滚动视图控件,其设计灵感来源于淘宝头条,旨在为开发者提供更丰富的滚动效果。该控件不仅支持基本的垂直滚动,还提供了四种不同的滚动模式,增强了用户体验。 ...

    android自定义垂直滚动选择器

    标题“android自定义垂直滚动选择器”暗示我们要讨论的是一个用于时间或日期选择的滚动视图,它能沿着垂直方向滚动,提供用户一个方便的选取方式。通常,这样的组件可以是自定义的时间选择器(TimePicker)或日期...

    ScrollBar(自定义滚动条)

    本主题将深入探讨如何在Android中自定义滚动条,包括横向和纵向的实现,以及如何将其应用到列表视图中。 首先,我们要了解默认的Android滚动条样式可能无法满足所有设计需求,因此自定义滚动条成为了提升用户体验的...

    Android-ShelfView一个用实际书架样式展示图书的Android自定义视图

    在Android应用开发中,自定义视图是一种常见的技术,它允许开发者根据特定需求设计和实现自己的组件。"Android-ShelfView"就是一个实例,它提供了一种以真实书架样式展示图书的方式,增强了用户界面的视觉效果和交互...

    Android自定义adapter的listview

    以上就是关于“Android自定义adapter的listview”的主要知识点。自定义Adapter是Android开发中的核心技能之一,掌握好这一技巧,能帮助我们实现各种复杂的界面效果。通过不断实践和优化,我们可以在保证性能的同时,...

    自定义滚动条

    对于移动应用,如iOS和Android,开发者同样可以自定义滚动条。在iOS中,可以使用`UIScrollIndicatorStyle`来设置滚动视图的指示器样式,或者自定义`UIScrollView`的子视图来实现完全自定义的滚动条。而在Android中,...

    Android自定义列表,可双向滚动

    HorizontalScrollView可以承载单个垂直滚动的View,而NestedScrollView则允许嵌套的滚动视图,这对于处理复杂交互很有用。 在实际项目中,"activity1"可能是实现这种双向滚动列表的主活动。在这个活动中,我们需要...

    android 自定义 模仿Launcher

    在Android开发中,自定义Launcher是一项常见的需求,它允许开发者创建独特的用户界面,提供与原生...通过分析和修改`ScrollLayoutGrid_v3`,可以深入了解Android自定义视图的实现,同时也可以提升解决实际问题的能力。

    AKParallax-Android,滚动视图.zip

    《AKParallax-Android:滚动视图中的视差效果实现》 在移动应用开发中,尤其是Android平台,用户界面的设计和交互体验对于提升应用的吸引力至关重要。为了使应用更具动态感和深度,开发者们常常会引入视差效果,即...

    使用 Android 旋转传感器并使用自定义视图可视化设备旋转的示例_Java_代码_相关文件_下载

    这是一个示例应用程序,它使用 Android 旋转传感器并使用自定义视图(姿态指示器,又名“人工地平线”)显示设备旋转(俯仰/滚动)。 它显示了以下 Android 功能的正确使用: 监控旋转矢量传感器(但仅在活动可见...

    Android中自定义滑动选中控件WheelView

    你分享的`WheelView-master`可能包含了这些实现细节和优化措施,通过对源码的学习,我们可以深入理解Android自定义控件的开发流程,以及如何实现复杂的交互效果。同时,这也是与其他开发者交流和学习的好机会,共同...

    移动应用开发_Android视图控件开发_全景360度自动循环滚动视图组件_用于创建支持自动和手动交互的全景展示效果实现平滑的无限循环或往复滚动可自定义滚动速度适用于产品展示.zip

    移动应用开发_Android视图控件开发_全景360度自动循环滚动视图组件_用于创建支持自动和手动交互的全景展示效果实现平滑的无限循环或往复滚动可自定义滚动速度适用于产品展示

    Android 自定义ViewFlipper 滚动效果

    要自定义滚动动画,你需要创建一个继承自ViewFlipper的类,并重写`onLayout()`和`onMeasure()`方法,确保正确处理子视图的布局。同时,你需要实现自己的动画逻辑,这通常涉及到对`startFlipping()`的重写,以及使用`...

Global site tag (gtag.js) - Google Analytics