转载请注明出处http://blog.csdn.net/u011453163/article/details/52960329
Android和ios应用开发虽然大同小异,但是对于原生sdk提供的组件来说,ios要相对美观点,但是Android 的组件也是可以高度自定义的,基本上ios有的Android都能自定义达到相同的效果。
今天通过对listview做一点点小修改实现一个wheelview的效果(滚筒选择器) 虽然网上已经有很多这样的效果,但有时候我只想实现一个比较简单的效果并不想去引入太多的类。。
先看效果图
这个选择器效果我只是在原来的listview上做了一些小修改,也踩了一些坑。
有两个点
1.数据循环
2.滑动后的回弹居中
第一点我用的是取余的方法,这个在循环的viewpager里应该很多人都用过了。
第二点回弹居中的效果 我用的是属性动画(ValueAnimator)而没用Scroller
关于第一点就不多说了,处理适配器的两个方法就可以了
@Override
public int getCount() {
return datas!=null?2000:0;
}
@Override
public String getItem(int position) {
return datas!=null?datas.get(position%datas.size()):null;
}
关于第二点回弹居中的效果
回弹居中效果,虽然listview有提供好几个平滑滚动的方法
smoothScrollToPosition(int position)
smoothScrollByOffset(int offset)
基本上带smooth的方法都是带有平滑效果的,但是都不是很理想,都有不能被接受的准确性,就是偏移了。
但是有一个方法是非常准确的
@Override
public void setSelection(int position) {
setSelectionFromTop(position, 0);
}
这个方法一点也不陌生,就是滚到指定位置的。虽然不知道为什么这个不会偏差,然后找到里面的
public void setSelectionFromTop(int position, int y)
很好,这个方法是可以直接用的。这个方法的效果是 滚动到指定的位置 偏移头的量,setSelectionFromTop(position, 0),就是setSelection(int position);
所以想到利用这个偏移量来达到回弹居中的效果 想法大概是这样的
因为listview的复用 ,所以保证listview的高是item的奇数倍数就好了,所以只要监听listview的滚动就可以了
@Override
public 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;
}
}
}
}
@Override
public 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()/23*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() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
v.setSelectionFromTop(position,((Integer) animation.getAnimatedValue()).intValue());
}
});
valueAnimator.setDuration(150);
valueAnimator.start();
}
这里就是用到了setSelectionFromTop(position,y)这个方法;
最后是划线的,上下蒙层效果
@Override
protected 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);
}
@Override
public 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;//选择字体大小 单位sp
private int defTextSize=15;//默认字体大小 单位sp
private 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);
}
@Override
public 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;
}
}
}
}
@Override
public 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()/23*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;
}
}
@Override
protected 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);
}
@Override
public 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() {
@Override
public 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的三倍最好,还没很完善的做好适配。