android自定义View之3D索引效果
2016-12-11 00:52
197 查看
效果图:
我的小霸王太卡了。
最近工作比较忙,今天搞了一下午才搞出来这个效果,这种效果有很多种实现方式,最常见的应该是用贝塞尔曲线实现的。今天我们来看另一种不同的实现方式,只需要用到 canvas.scale(),有没有很好奇是怎么实现的呢。
首先来说一下思路,只要有了思路剩下的就是往里面套代码了。
通过观察上面的效果图我们发现可以把右边的字母分为三种类型
1、 手指没触摸的地方显示正常的样式
2、手指触摸的位置 显示最大且完全不透明
3、手指触摸位置的上下附近位置 有放大且有透明度变化
对这个效果有了直观的认识后,我们就可以在ondraw里面根据不同的条件来分别画出这三种状态,这里主要难理解的就是这些条件。这需要结合代码看下。
so 我们开始撸码吧,
1、先初始化一些需要的变量
相信上面这些应该没什么难度吧。
另外把一些需要的宽高属性赋值一下,因为下面会用到它们
这里主要就是mIsDownRect这个要注意一下它是索引列表的范围,但是我们并不需要画出它。
2、在ontouch方法中对触摸事件进行必要的处理
这里面也很简单,首先当手指按下时记录下按下位置的Y坐标,然后判断按下的位置是否在索引列表的区域范围内(索引的区域在初始化赋值的时候已经确定过了)如果不在就没必要执行下去了 直接返回false即可,
然后在手指移动的时候判断下是否是在移动是的话就把mIsBeingDragger置为true,如果mIsBeingDragger为true说明正在移动 ,这时候就计算出当前手指所在的索引位置,并通过回调方式通知外面当前的位置,最后把索引位置赋给全局变量mChoose,并刷新UI。
手指抬起时进行一些复位操作。
以上就是ontouch的全部方法。
3、在ondraw方法里面画出索引字母
这里要画出那三种类型的字母索引,我们先从简单的来
mChoose 是在ontouch中我们记录的索引位置,当上面条件成立时说明当前就是选中的字母,这时候让它缩放比例最大,偏移量我们会在下面统一处理。
接下来处理不是选中的情况
这里主要就是那个缩放系数比较难算 需要多试下。
X Y方向的偏移量如下图
这些都计算好后就可以画了
可以发现canvas.scale(diff,diff,mWidth*1.2f+diffX,lettersPos+diffY); 这一句才是整个自定义view的关键 它前两个参数是x轴和y轴的缩放系数,后两个参数是x轴和y轴的锚点,我主要是试出来的,这两个参数比较难理解,还需要多家学习。到这里就已经实现了我们最上面的效果了。
源码
我的小霸王太卡了。
最近工作比较忙,今天搞了一下午才搞出来这个效果,这种效果有很多种实现方式,最常见的应该是用贝塞尔曲线实现的。今天我们来看另一种不同的实现方式,只需要用到 canvas.scale(),有没有很好奇是怎么实现的呢。
首先来说一下思路,只要有了思路剩下的就是往里面套代码了。
通过观察上面的效果图我们发现可以把右边的字母分为三种类型
1、 手指没触摸的地方显示正常的样式
2、手指触摸的位置 显示最大且完全不透明
3、手指触摸位置的上下附近位置 有放大且有透明度变化
对这个效果有了直观的认识后,我们就可以在ondraw里面根据不同的条件来分别画出这三种状态,这里主要难理解的就是这些条件。这需要结合代码看下。
so 我们开始撸码吧,
1、先初始化一些需要的变量
private void init(Context context) { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.GRAY); mLetters = context.getResources().getStringArray(R.array.letter_list); mPaint.setTextAlign(Paint.Align.CENTER); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mDensity = getContext().getResources().getDisplayMetrics().density; setPadding(0,dip2px(20),0,dip2px(20)); } private int dip2px(int dipPx){ return (int)(dipPx*mDensity+0.5); }
相信上面这些应该没什么难度吧。
另外把一些需要的宽高属性赋值一下,因为下面会用到它们
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mHeight = h - getPaddingTop() - getPaddingBottom(); mWidth = w - dip2px(16); mLetterHeight = mHeight / mLetters.length; int textSize = (int)(mLetterHeight*0.7); mPaint.setTextSize(textSize); mIsDownRect.set(w-dip2px(32),0,w,h); }
这里主要就是mIsDownRect这个要注意一下它是索引列表的范围,但是我们并不需要画出它。
2、在ontouch方法中对触摸事件进行必要的处理
public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action){ case MotionEvent.ACTION_DOWN: mIsBeingDragger = false; float initDownY = event.getY(); if(!mIsDownRect.contains(event.getX(),event.getY())){ return false; } mInitDownY = initDownY; break; case MotionEvent.ACTION_MOVE: float y = event.getY(); float diff = Math.abs(y - mInitDownY); if(diff>mTouchSlop&&!mIsBeingDragger){ mIsBeingDragger = true; } if(mIsBeingDragger){ mY = y; float moveY = y - getPaddingTop(); int chartIndex = (int) (moveY / mHeight * mLetters.length);//获取索引位置的index if(mChoose!=chartIndex){ if(chartIndex>=0&&chartIndex<mLetters.length) { if (slidViewListener != null) { Log.i("lly","chartIndex = "+chartIndex); slidViewListener.onChange(mLetters[chartIndex]); } mChoose = chartIndex; } } invalidate(); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mIsBeingDragger = false; mChoose = -1; invalidate(); break; } return true; }
这里面也很简单,首先当手指按下时记录下按下位置的Y坐标,然后判断按下的位置是否在索引列表的区域范围内(索引的区域在初始化赋值的时候已经确定过了)如果不在就没必要执行下去了 直接返回false即可,
然后在手指移动的时候判断下是否是在移动是的话就把mIsBeingDragger置为true,如果mIsBeingDragger为true说明正在移动 ,这时候就计算出当前手指所在的索引位置,并通过回调方式通知外面当前的位置,最后把索引位置赋给全局变量mChoose,并刷新UI。
手指抬起时进行一些复位操作。
以上就是ontouch的全部方法。
3、在ondraw方法里面画出索引字母
这里要画出那三种类型的字母索引,我们先从简单的来
float lettersPos= mLetterHeight*(i+1)+getPaddingTop(); //下一个字母的Y值坐标 float diffY; // Y 方向的偏移量 float diffX;//X 方向的偏移量 float diff;//缩放比例 if (mChoose == i&&i!=0&&i!=mLetters.length-1) { diff = 2.2f; diffX=0f; diffY=0f; }
mChoose 是在ontouch中我们记录的索引位置,当上面条件成立时说明当前就是选中的字母,这时候让它缩放比例最大,偏移量我们会在下面统一处理。
接下来处理不是选中的情况
float distanseDiff = Math.abs((mY - lettersPos)/mHeight);//计算手指触摸位置的上下附近位置 float maxPos = distanseDiff * 7;//乘7是因为这个系数太小了需要给他一个放大 if(distanseDiff<0.174){ diff = 2.2f - maxPos; }else { diff = 1f; } if(!mIsBeingDragger){ diff =1; } diffX = maxPos * 50; if(mY>lettersPos){ diffY = maxPos*50; }else { diffY = - maxPos*50; }
这里主要就是那个缩放系数比较难算 需要多试下。
X Y方向的偏移量如下图
这些都计算好后就可以画了
canvas.save(); canvas.scale(diff,diff,mWidth*1.2f+diffX,lettersPos+diffY); if(diff ==1){ mPaint.setAlpha(255); mPaint.setTypeface(Typeface.DEFAULT); }else { int alpha = (int) (255*(1-Math.min(0.9,diff -1))); if(mChoose == i){ alpha = 255; } mPaint.setAlpha(alpha); mPaint.setTypeface(Typeface.DEFAULT_BOLD); } Log.i("lly","mLetters["+i+"] = " +mLetters[i] ); canvas.drawText(mLetters[i],mWidth,lettersPos,mPaint); canvas.restore();
可以发现canvas.scale(diff,diff,mWidth*1.2f+diffX,lettersPos+diffY); 这一句才是整个自定义view的关键 它前两个参数是x轴和y轴的缩放系数,后两个参数是x轴和y轴的锚点,我主要是试出来的,这两个参数比较难理解,还需要多家学习。到这里就已经实现了我们最上面的效果了。
源码
相关文章推荐
- android自定义View之3D索引效果
- android自定义ViewPager之——3D效果应用
- 仿IOS特效(一)——Android 自定义View实现3D滚轮效果的城市联动选择器
- Android自定义View实现HTML图文环绕效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- Android UI:看看Google官方自定义带旋转动画的ImageView-----RotateImageView怎么写(附 图片淡入淡出效果)
- Android 自定义View (三) 圆环交替 等待效果
- android自定义view仿照MIUI中音量控制效果
- Android自定义View实现HTML图文环绕效果
- android 自定义 3D效果饼图
- Android 自定义View (三) 圆环交替 等待效果
- 利用Android自定义View实现转盘旋转的效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- Android自定义View实现转盘旋转的效果
- Android 自定义View (三) 圆环交替 等待效果
- 实现自定义view(2):仿Android QQ多屏幕显示ListView的效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- Android自定义ViewGroup自动换行实现滑动任意布局及事件处理效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- Android 自定义View (三) 圆环交替 等待效果