100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Android自定义UI实战(基础篇3)---图标圆弧运动

Android自定义UI实战(基础篇3)---图标圆弧运动

时间:2021-06-10 00:45:57

相关推荐

Android自定义UI实战(基础篇3)---图标圆弧运动

先上效果:

实现基本步骤;

1.背景和圆弧的绘制:在此使用到背景图片如下,我们可以根据需求更换成自己的图片

2.图标源着圆弧绘制

3.左滑,右滑的处理

一 、圆弧背景的实现

关于背景的截取,在此使用BitmapShader来实现,不明白BitmapShader实现原理的可以学习一下这篇文章:

/harvic880925/article/details/52039081

/*** 绘制背景*/private void drawBackground(Canvas canvas) {Bitmap bitmapBg = BitmapFactory.decodeResource(getResources(), R.drawable.bg); //取得背景图片Bitmap bitmap = Bitmap.createScaledBitmap(bitmapBg, width, height, false); //将取得的背景图片压缩到指定的大小if (bitmapBg != null) {//设置重复模式,TileMode.CLAMP:用边缘色彩填充多余空间mPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));Bitmap des = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);Canvas c = new Canvas(des);Paint paint = new Paint();c.drawCircle(width / 2, -radius/2, radius, mPaint); //绘制圆弧canvas.drawBitmap(des, 0, 0, paint);}}

在绘制圆弧取得的中心点为 (width/2 ,-radius/2);在这里半径设置为800,实际绘制出来的圆如下图所示:

在我们屏幕上看到的效果如下:

在ondraw 里面调用drawBackground 方法就可以得到了一个圆弧背景。

二、图标的绘制

在此绘制五个图标,设置图片id

private int[] src = new int[]{R.drawable.pic1,R.drawable.pic2,R.drawable.pic3,R.drawable.pic4,R.drawable.pic5,};private int[] srcTemp = new int[]{R.drawable.pic1,R.drawable.pic2,R.drawable.pic3,R.drawable.pic4,R.drawable.pic5,};private int[] srcSlect = new int[]{R.drawable.pic_slect1,R.drawable.pic_slect2,R.drawable.pic_slect3,R.drawable.pic_slect4,R.drawable.pic_slect5,};

在此src存储的是变换前的id,src存储的为变化之后的id,为变化之前的初始化时一样的。 srcSlect存储的为选中状态图标的id

下面来看代码的实现

/*** 绘制圆弧上面显示的图标* @param canvas*/private void drawIcon(Canvas canvas) {float scaleValue; //缩放比例值int x1, y1;Bitmap bitmap;Matrix matrix = new Matrix();centerX = width / 2;centerY = radius/2;for (int i = 1; i < 10; i += 2) { //将屏幕分为10份,取 1 3 5 7 9 来作为显示位置//取得相对应的bitmapif (i < 2) {bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), srcTemp[0]), picSize, picSize, false);} else {bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), srcTemp[i / 2]), picSize, picSize, false);}//取得下一个图片的x , Y 轴坐标x1 = (width) / 10 * i - picSize / 2;y1 = (int) Math.sqrt(Math.pow(radius, 2) - Math.pow((width / 2 - (width) / 10 * i), 2)) - radius/2 - picSize/2;scaleValue = scaleValues[i/2]; //获取缩放比例matrix.reset();matrix.setTranslate(x1, y1);matrix.postScale(scaleValue, scaleValue,centerX,centerY); //按比例缩放canvas.drawBitmap(bitmap, matrix, null); //将bitmap绘制到画布上}}

实现的主要核心是取得5个图标的坐标:

//取得下一个图片的x , Y 轴坐标

x1 = (width) / 10 * i - picSize / 2;y1 = (int) Math.sqrt(Math.pow(radius, 2) - Math.pow((width / 2 - (width) / 10 * i), 2)) - radius/2 - picSize/2;

x轴坐标取得比较简单,来看Y轴坐标的取得

由上图可以看出,因为已经知道了X轴的坐标,因此可以得到每个点的Y轴坐标。

这样,实现了图标源着圆弧绘制。效果如下:

三 滑动的处理

在滑动过程中,图标都是循环的,因此要实现图标的循环,要做的是实现图标id数值坐标的循环,实现如下:

/*** 滑动处理* 分为向左滑动,和向右滑动*/private void smoothToLeftOrRight(int type) {int position = 0;if (type == SMOOTH_TO_LEFT) { //向左滑动和向右滑动,坐标变化++index;if (index >= src.length) index = 0;} else if (type == SMOOTH_TO_RIGHT) {--index;if (index < 0) index = src.length - 1;}//实现循序数组for (int i = 0; i < src.length; i++) {position = (index + i);if (position >= src.length) {position -= src.length;}srcTemp[i] = src[position];}if (index <= 2) {centerPosition = index + 2;} else {centerPosition = index - 3;}srcTemp[2] = srcSlect[centerPosition]; //设置最中间的图标为选中状态postInvalidate();}

实现比较简单,主要是在滑动的时候将数组src进行循环排序后保存到srcTemp里面,然后重绘页面,将排序后的图标显示出来。下面来看滑动的判断

@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:downX = (int) event.getX();downY = (int) event.getY();return true;case MotionEvent.ACTION_MOVE:return true;case MotionEvent.ACTION_UP:int moveX = (int) event.getX();int moveY = (int) event.getY();smoothDistance = moveX - downX;if (smoothDistance < -100) {smoothToLeftOrRight(SMOOTH_TO_LEFT);} else if (smoothDistance > 100) {smoothToLeftOrRight(SMOOTH_TO_RIGHT);}return true;}return super.onTouchEvent(event);}

在 MotionEvent.ACTION_UP: 里面来判断向左向右滑动, 然后调用smoothToLeftOrRight 方法后实现滑动后图标的刷新。

在实现了上面功能后,来给中间图标添加点击事件,在这里通过判断点击的位置是否在图标所在区域内,判断代码如下:

boolean isclick = new Rect(centerX - picSize / 2, centerY - picSize / 2, centerX + picSize / 2, centerY + picSize / 2).contains(downX, downY);if(isclick){onclickListener.itemOnclickListener(centerPosition);}

通过回调,就可以获取到点击的当前位置了(此位置为初始化图标所在的位置)。

至此,已经基本上实现了开篇效果的功能(注:在使用过程中的一些数据,直接是写死的。我们可能通过自定义属性,去自定义某些参数)。

完整实现代码如下:

/*** author: Mirko* date : -10-18 14:08* 对象随着圆的半径移动*/public class CicleSliding extends View {private static final int SMOOTH_TO_LEFT = 1; //定义向左向右滑动private static final int SMOOTH_TO_RIGHT = 2;private int width = 800, height = 400;private int radius = 800;//设置绘制的圆的半径private Context mContext;private Paint mPaint;private int index = 0;private int centerX, centerY;private int mSize;private int downX, downY; //按下的X,Y轴坐标private int picSize = 120; //设置需要绘制的图片的大小private int smoothDistance =0; //滑动间距private int centerPosition = 2; //最中间位置的坐标private int[] src = new int[]{R.drawable.pic1,R.drawable.pic2,R.drawable.pic3,R.drawable.pic4,R.drawable.pic5,};private int[] srcTemp = new int[]{R.drawable.pic1,R.drawable.pic2,R.drawable.pic3,R.drawable.pic4,R.drawable.pic5,};private int[] srcSlect = new int[]{R.drawable.pic_slect1,R.drawable.pic_slect2,R.drawable.pic_slect3,R.drawable.pic_slect4,R.drawable.pic_slect5,};private float[] scaleValues = new float[]{1f,1f,1.1f,1f,1f}; //缩放比例public CicleSliding(Context context) {super(context);mContext = context;init();}public CicleSliding(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;init();}public CicleSliding(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;init();}private void init() {width = ViewSizeHelper.getDeviceWidth((Activity) mContext);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setColor(0xffff2222);srcTemp[src.length / 2] = srcSlect[srcSlect.length / 2];}protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mSize = Math.min(getMeasuredWidth(), getMeasuredHeight());setMeasuredDimension(mSize, mSize);}/*** 绘制背景*/private void drawBackground(Canvas canvas) {Bitmap bitmapBg = BitmapFactory.decodeResource(getResources(), R.drawable.bg); //取得背景图片Bitmap bitmap = Bitmap.createScaledBitmap(bitmapBg, width, height, false); //将取得的背景图片压缩到指定的大小if (bitmapBg != null) {//设置重复模式,TileMode.CLAMP:用边缘色彩填充多余空间mPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));Bitmap des = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);Canvas c = new Canvas(des);Paint paint = new Paint();c.drawCircle(width / 2, -radius/2, radius, mPaint); //绘制圆弧canvas.drawBitmap(des, 0, 0, paint);}}/*** 绘制圆弧上面显示的图标* @param canvas*/private void drawIcon(Canvas canvas) {float scaleValue; //缩放比例值int x1, y1;Bitmap bitmap;Matrix matrix = new Matrix();centerX = width / 2;centerY = radius/2;for (int i = 1; i < 10; i += 2) { //将屏幕分为10份,取 1 3 5 7 9 来作为显示位置//取得相对应的bitmapif (i < 2) {bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), srcTemp[0]), picSize, picSize, false);} else {bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), srcTemp[i / 2]), picSize, picSize, false);}//取得下一个图片的x , Y 轴坐标x1 = (width) / 10 * i - picSize / 2;y1 = (int) Math.sqrt(Math.pow(radius, 2) - Math.pow((width / 2 - (width) / 10 * i), 2)) - radius/2 - picSize/2;scaleValue = scaleValues[i/2]; //获取缩放比例matrix.reset();matrix.setTranslate(x1, y1);matrix.postScale(scaleValue, scaleValue,centerX,centerY); //按比例缩放canvas.drawBitmap(bitmap, matrix, null); //将bitmap绘制到画布上}}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:downX = (int) event.getX();downY = (int) event.getY();boolean isclick = new Rect(centerX - picSize / 2, centerY - picSize / 2, centerX + picSize / 2, centerY + picSize / 2).contains(downX, downY);if(isclick){onclickListener.itemOnclickListener(centerPosition);}return true;case MotionEvent.ACTION_MOVE:return true;case MotionEvent.ACTION_UP:int moveX = (int) event.getX();int moveY = (int) event.getY();smoothDistance = moveX - downX;if (smoothDistance < -100) {smoothToLeftOrRight(SMOOTH_TO_LEFT);} else if (smoothDistance > 100) {smoothToLeftOrRight(SMOOTH_TO_RIGHT);}return true;}return super.onTouchEvent(event);}/*** 滑动处理* 分为向左滑动,和向右滑动*/private void smoothToLeftOrRight(int type) {int position = 0;if (type == SMOOTH_TO_LEFT) { //向左滑动和向右滑动,坐标变化++index;if (index >= src.length) index = 0;} else if (type == SMOOTH_TO_RIGHT) {--index;if (index < 0) index = src.length - 1;}//实现循序数组for (int i = 0; i < src.length; i++) {position = (index + i);if (position >= src.length) {position -= src.length;}srcTemp[i] = src[position];}if (index <= 2) {centerPosition = index + 2;} else {centerPosition = index - 3;}srcTemp[2] = srcSlect[centerPosition]; //设置最中间的图标为选中状态Log.d("test", "index:" + index);postInvalidate();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int layerId = canvas.saveLayer(0, 0, width, height, mPaint, Canvas.ALL_SAVE_FLAG);drawBackground(canvas); //绘制背景canvas.restoreToCount(layerId);drawIcon(canvas);}public interface OnclickListener{public void itemOnclickListener(int index);}private OnclickListener onclickListener;public void setOnclickListener(OnclickListener onclickListener){this.onclickListener = onclickListener;}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。