安卓自定义控件(图像循环切换)



源码下载http://download.csdn.net/detail/scimence/9027447


package com.sci.circularviewswitching;

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


/**
 * MainActivity
 * -----
 * 2015-8-18 下午4:48:07 
 * wangzhongyuan
 */
public class MainActivity extends Activity
{
	int[] PicId = { R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6, R.drawable.pic7, R.drawable.pic8 };

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		
		CircularImageView main = new CircularImageView(this, PicId); 	// 创建主视图
		setContentView(main);											// 设置为游戏视图
		// setContentView(R.layout.activity_main);
	}
}

/**
 * 2015-8-19上午9:48:34
 * wangzhongyuan
 */

package com.shjc.jsbc.view2d.util;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.RelativeLayout;
import android.widget.Toast;


/**
 * CircularImageView 此类用于实现多张ImageView的层叠展示循环切换,中间图像最前端显示,向两边图像尺寸依次递减
 * selected()获取当前最前端显示的控件id
 * -----
 * 2015-8-19 上午9:48:34 
 * wangzhongyuan
 */
public class CircularImageView extends RelativeLayout implements OnTouchListener, android.view.View.OnClickListener
{
	private Context context;		// 控件所处的上下文环境
	private int[] PicId;			// 控件所要展示的子图像
	private int len;				// 子图像总数
	private ImageView2[] pics;		// 子图像数组
	private int offSet = 0;			// 图像显示偏移值,控制图像的显示位置
	private float x1 = -1, y1 = -1, x2 = -1, y2 = -1;				// 标志触摸按下和触摸释放时的坐标
			
	/**
	 * 获取当前选中的子控件id = [0, len)
	 */
	public int selected()
	{
		// 选中图像id
		int id = len / 2 + offSet;
		if (id >= len)
			id -= len;
		else if (id < 0) id += len;
		
		return id;
	}
	
	/**
	 * 选中子控件变动时调用该函数,子类可重写该函数,执行子控件选项变动逻辑
	 */
	public void selecteChanged()
	{
		// if(selected() == 0) ...;
		// else if(selected() == 1) ...;
	}
	
	/**
	 *  创建控件, PicId = { R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5};
	 */
	public CircularImageView(Context context, int[] PicId)
	{
		super(context);
		
		this.context = context;
		this.PicId = PicId;
		len = PicId.length;
		offSet = -len / 2;	// 初始时,显示第一项到最中间
		
		creatMainView();
	}
	
	// 创建CircularImageView的子控件,以代码布局的方式显示PicId对应的图像
	private void creatMainView()
	{
		int w = 480, h = 300;		// CircularImageView整体大小
		int w2 = 264, h2 = 165;		// CircularImageView最中间位置的ImageView展示大小
		
		// 控件主体部分
		RelativeLayout body = new RelativeLayout(context);	// 创建一个相对布局的视图
		body.setBackgroundColor(Color.GRAY); 				// 为其设置背景色
		body.setOnTouchListener(this);						// 为CircularImageView添加触屏响应
		
		// 添加游戏主体部分到主界面
		RelativeLayout.LayoutParams paramsBody = new RelativeLayout.LayoutParams(w, h);
		paramsBody.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
		this.addView(body, paramsBody);
		
		pics = new ImageView2[len];
		
		for (int i = 0; i < len; i++)
		{
			// 修改控件的显示顺序
			int j = i, half = len / 2;
			if (i >= half) j = len - 1 - (i - half);
			
			// 向body中添加子控件
			ImageView2 pic = new ImageView2(context, j - half);
			RelativeLayout.LayoutParams params = getLayoutParams(w / 2, h / 2, w2, h2, j);
			body.addView(pic, params);						// 将表示方格的文本框添加到窗体
			
			pic.setScaleType(ScaleType.CENTER_CROP);
			pic.setBackgroundResource(getPicId(PicId, j));
			pics[j] = pic;
			
			pic.setOnClickListener(this);					// 添加事件监听
		}
		
		pics[len / 2].setOnTouchListener(this);				// 为中间位置的子控件添加触屏响应
	}
	
	// 根据偏移值,循环获取图像资源对应的索引
	private int getPicId(int[] PicId, int i)
	{
		i += offSet;
		if (i >= len)
			i -= len;
		else if (i < 0) i += len;
		
		return PicId[i];
	}
	
	// 获取第index项的布局参数,界面从0-len项依次布局,最中间的那项居中显示,从中间向两边尺寸依次递减
	private RelativeLayout.LayoutParams getLayoutParams(int CenterX, int CenterY, int w, int h, int index)
	{
		int len = this.len, half = len / 2;
		if (len % 2 == 0) len++;
		index %= len;
		
		int Sign = index >= half ? 1 : -1;
		int W = getHalfWH(w, index - half);
		int H = getHalfWH(h, index - half);
		int sumW = getHalfWH_sum(w, index - half) * Sign;
		// int sumH = getHalfWH_sum(h, index - half);
		
		RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(W, H);
		
		int left = CenterX + sumW - W / 2, top = CenterY - H / 2, right = left + W + 1, bottom = top + H + 1;
		params.setMargins(left, top, right, bottom);	// 设置index对应的View的布局位置
		
		return params;
	}
	
	// 长宽值WH经过n次折半
	private int getHalfWH(int WH, int n)
	{
		n = Math.abs(n);
		while (n-- > 0)
			WH /= 2;
		
		return WH;
	}
	
	// 长宽值WH经过n次折半,偏移量累积值
	private int getHalfWH_sum(int WH, int n)
	{
		n = Math.abs(n);
		int sum = 0;
		while (n-- > 0)
		{
			WH /= 2;
			sum += WH;
		}
		
		return sum;
	}
	
	/* 点击界面中的View,切换显示至最前端 */
	@SuppressLint("HandlerLeak")
	@Override
	public void onClick(View arg0)
	{
		if (arg0 instanceof ImageView2)
		{
			int half = len / 2;
			ImageView2 view = (ImageView2) arg0;
			if (view.offSet == 0) return;
			
			// 根据点击的ImageView位置,为所有子控件添加简单的动画切换效果
			for (int i = 0; i < len; i++)
			{
				if (i < half)
					aniScale(pics[i], view.offSet < 0);
				else if (i > half)
					aniScale(pics[i], view.offSet > 0);
				else
					aniScale(pics[i], false);
			}
			
			// 根据点击控件位置,设置图像偏移值
			offSet += view.offSet;
			if (offSet >= len)
				offSet -= len;
			else if (offSet < 0) offSet += len;
			
			// 延时执行切换显示动作
			new Handler()
			{
				public void handleMessage(Message msg)
				{
					for (int i = 0; i < len; i++)
					{
						pics[i].setBackgroundResource(getPicId(PicId, i));
					}
				}
			}.sendEmptyMessageDelayed(1, 55L);
			
			// 执行选中子控件变动逻辑
			selecteChanged();
			
			// 选中图像提示信息
			Toast.makeText(context, "选中图像" + selected(), Toast.LENGTH_SHORT).show();
		}
	}
	
	// 为视图v添加动画效果,尺寸变化
	private void aniScale(View v, boolean amplify)
	{
		// v.bringToFront(); //前端显示
		
		AnimationSet aniSet = new AnimationSet(true);
		
		// 设置尺寸从1倍变化到1.7倍
		ScaleAnimation scaleAni;
		if (amplify)
			scaleAni = new ScaleAnimation(1f, 1.75f, 1f, 1.75f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		else
			scaleAni = new ScaleAnimation(1f, 0.45f, 1f, 0.45f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		
		scaleAni.setDuration(50);		// 设置动画效果时间
		aniSet.addAnimation(scaleAni);	// 将动画效果添加到动画集中
		
		v.startAnimation(aniSet);		// 视图v开始动画效果
	}
	
	// 为每个ImageView添加offSet属性值,记录相对于中间ImageView的偏移量
	class ImageView2 extends ImageView
	{
		int offSet = -1;
		
		ImageView2(Context context, int offSet)
		{
			super(context);
			this.offSet = offSet;
		}
	}
	
	/* 触屏响应 */
	public boolean onTouch(View v, MotionEvent event)
	{
		// 获取触摸拖动起点和终点的坐标,以便于判断触摸移动方向
		switch (event.getAction())
		{
			case MotionEvent.ACTION_DOWN:	// 触摸屏幕后记录坐标
				x1 = event.getX();			// 按下点坐标
				y1 = event.getY();
				break;
			
			case MotionEvent.ACTION_MOVE:	// 触摸移动
				break;
			
			case MotionEvent.ACTION_UP:
				x2 = event.getX();			// 移动点坐标
				y2 = event.getY();
				
				if (x2 - x1 > 6) onClick(pics[len / 2 - 1]);		// 向右滑动
				else if (x2 - x1 < -6) onClick(pics[len / 2 + 1]);	// 向左滑动
					
				break;
			
			case MotionEvent.ACTION_CANCEL:
		}
		return true;
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值