转载请注明出处http://blog.csdn.net/u011453163/article/details/52960329
Android和ios应用开发虽然大同小异,但是对于原生sdk提供的组件来说,ios要相对美观点,但是Android 的组件也是可以高度自定义的,基本上ios有的Android都能自定义达到相同的效果。
今天通过对listview做一点点小修改实现一个wheelview的效果(滚筒选择器) 虽然网上已经有很多这样的效果,但有时候我只想实现一个比较简单的效果并不想去引入太多的类。。
先看效果图
这个选择器效果我只是在原来的listview上做了一些小修改,也踩了一些坑。
有两个点
1.数据循环
2.滑动后的回弹居中
第一点我用的是取余的方法,这个在循环的viewpager里应该很多人都用过了。
第二点回弹居中的效果 我用的是属性动画(ValueAnimator)而没用Scroller
关于第一点就不多说了,处理适配器的两个方法就可以了
@Overridepublic int getCount() {return datas!=null?2000:0;}@Overridepublic String getItem(int position) {return datas!=null?datas.get(position%datas.size()):null;}
关于第二点回弹居中的效果
回弹居中效果,虽然listview有提供好几个平滑滚动的方法
smoothScrollToPosition(int position)
smoothScrollByOffset(int offset) 基本上带smooth的方法都是带有平滑效果的,但是都不是很理想,都有不能被接受的准确性,就是偏移了。
但是有一个方法是非常准确的
@Overridepublic void setSelection(int position) {setSelectionFromTop(position, 0);}
这个方法一点也不陌生,就是滚到指定位置的。虽然不知道为什么这个不会偏差,然后找到里面的
public void setSelectionFromTop(int position, int y)
很好,这个方法是可以直接用的。这个方法的效果是 滚动到指定的位置 偏移头的量,setSelectionFromTop(position, 0),就是setSelection(int position);
所以想到利用这个偏移量来达到回弹居中的效果 想法大概是这样的
因为listview的复用 ,所以保证listview的高是item的奇数倍数就好了,所以只要监听listview的滚动就可以了
@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if(scrollState==SCROLL_STATE_IDLE){if(view instanceof ListView){View v = view.getChildAt(0);int position= view.getFirstVisiblePosition();if(-v.getTop()>v.getHeight()/2){ScrollAnim((ListView) view,position, v.getTop(),-v.getHeight());selectPosition=position+1;}else {ScrollAnim((ListView) view,position, v.getTop(),0);selectPosition=position;}}}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {if(view instanceof ListView){for (int i = 0; i < view.getChildCount(); i++) {View v=view.getChildAt(i);if(v instanceof TextView){if(v.getY()+v.getHeight()/2>view.getHeight()/3&&v.getY()+v.getHeight()/2<view.getHeight()/3*2){((TextView) v).setTextColor(selectColor);((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_SP,selectTextSize);}else {((TextView) v).setTextColor(defColor);((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_SP,defTextSize);}}}}}
onScrollStateChanged里做的事是在滑动停止以后做回弹居中的效果
onScroll里是做了滑动过程中的一些选中变化,这里是做了字体颜色和大小的变化。
if(scrollState==SCROLL_STATE_IDLE){if(view instanceof ListView){View v = view.getChildAt(0);int position= view.getFirstVisiblePosition();if(-v.getTop()>v.getHeight()/2){ScrollAnim((ListView) view,position, v.getTop(),-v.getHeight());selectPosition=position+1;}else {ScrollAnim((ListView) view,position, v.getTop(),0);selectPosition=position;}}}
停止以后 计算第一个显示的item的偏移量 以决定是向上滚动或者向下滚动,平滑滚动是用的属性动画api ValueAnimator
private void ScrollAnim(final ListView v, final int position, int y1, int y2){ValueAnimator valueAnimator= ValueAnimator.ofInt(y1,y2);valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {v.setSelectionFromTop(position,((Integer) animation.getAnimatedValue()).intValue());}});valueAnimator.setDuration(150);valueAnimator.start();}
这里就是用到了setSelectionFromTop(position,y)这个方法;
最后是划线的,上下蒙层效果
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawLine(20,getHeight()/3,getWidth()-20,getHeight()/3,paintLine);canvas.drawLine(20,getHeight()/3*2,getWidth()-20,getHeight()/3*2,paintLine);}@Overridepublic void draw(Canvas canvas) {initFirst();canvas.saveLayer(0,0,this.getWidth(),this.getHeight(),null,Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);super.draw(canvas);paintShader.setShader(shaderTop);canvas.drawRect(0, 0, this.getWidth(), 100,paintShader);paintShader.setShader(shaderButtom);canvas.drawRect(0, this.getHeight()-100,this.getWidth(), this.getHeight(),paintShader);}
详细的看代码。
package com.weizhenbin.show.widget;import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.TextView;/*** Created by weizhenbin on 2016/10/26.*/
public class WheelListView extends ListView implements AbsListView.OnScrollListener {private Paint paintLine,paintShader;private int selectColor= Color.BLUE;//选择字体颜色private int defColor= Color.BLACK;//默认字体颜色private int selectTextSize=20;//选择字体大小 单位spprivate int defTextSize=15;//默认字体大小 单位spprivate LinearGradient shaderTop;private LinearGradient shaderButtom;private boolean hasInit=false;public int selectPosition;public WheelListView(Context context) {this(context,null);}public WheelListView(Context context, AttributeSet attrs) {this(context, attrs,0);}public WheelListView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);setOnScrollListener(this);paintLine=new Paint();paintLine.setStrokeWidth(2);paintLine.setColor(selectColor);}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if(scrollState==SCROLL_STATE_IDLE){if(view instanceof ListView){View v = view.getChildAt(0);int position= view.getFirstVisiblePosition();if(-v.getTop()>v.getHeight()/2){ScrollAnim((ListView) view,position, v.getTop(),-v.getHeight());selectPosition=position+1;}else {ScrollAnim((ListView) view,position, v.getTop(),0);selectPosition=position;}}}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {if(view instanceof ListView){for (int i = 0; i < view.getChildCount(); i++) {View v=view.getChildAt(i);if(v instanceof TextView){if(v.getY()+v.getHeight()/2>view.getHeight()/3&&v.getY()+v.getHeight()/2<view.getHeight()/3*2){((TextView) v).setTextColor(selectColor);((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_SP,selectTextSize);}else {((TextView) v).setTextColor(defColor);((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_SP,defTextSize);}}}}}private void initFirst() {if(!hasInit){paintShader =new Paint();paintShader.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));shaderTop=new LinearGradient(0, 0, 0, 100, 0xFF000000, 0,Shader.TileMode.CLAMP);shaderButtom=new LinearGradient(0, this.getHeight()-100, 0, this.getHeight(), 0, 0xFF000000,Shader.TileMode.CLAMP);hasInit=true;}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawLine(20,getHeight()/3,getWidth()-20,getHeight()/3,paintLine);canvas.drawLine(20,getHeight()/3*2,getWidth()-20,getHeight()/3*2,paintLine);}@Overridepublic void draw(Canvas canvas) {initFirst();canvas.saveLayer(0,0,this.getWidth(),this.getHeight(),null,Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);super.draw(canvas);paintShader.setShader(shaderTop);canvas.drawRect(0, 0, this.getWidth(), 100,paintShader);paintShader.setShader(shaderButtom);canvas.drawRect(0, this.getHeight()-100,this.getWidth(), this.getHeight(),paintShader);}/*** 平滑滚动* */private void ScrollAnim(final ListView v, final int position, int y1, int y2){ValueAnimator valueAnimator= ValueAnimator.ofInt(y1,y2);valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {v.setSelectionFromTop(position,((Integer) animation.getAnimatedValue()).intValue());}});valueAnimator.setDuration(150);valueAnimator.start();}public void setSelectColor(int selectColor) {this.selectColor = selectColor;}public void setDefColor(int defColor) {this.defColor = defColor;}public void setSelectTextSize(int selectTextSize) {this.selectTextSize = selectTextSize;}public void setDefTextSize(int defTextSize) {this.defTextSize = defTextSize;}
}
好到此就分享完了,这里只是给一个思路而已,如果有幸被使用,注意的是 WheelListView的高度是item的三倍最好,还没很完善的做好适配。