Android扇形选择器

/**
 * 扇形选择器
 *
 */
public class SelectView extends RelativeLayout {
    MyView myView;
    //touch的point
    private float oldX,oldY;
    private float originTouchPointX,originTouchPointY;
    //点击的第几圈
    private int circleNum;
    private SelectViewAdapter adapter;
    private Paint paint=new Paint();
    private SelectViewResultListener resultListener;
    private boolean anitionFinish=true;
    public SelectView(Context context,AttributeSet attributeSet) {
        // TODO Auto-generated constructor stub
        super(context, attributeSet);
        myView=new MyView(context);
        myView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        myView.setBackgroundColor(Color.TRANSPARENT);
        this.addView(myView);
    }
    public void setAdapter(SelectViewAdapter adapter){
        this.adapter=adapter;
        adapter.setServiceView(this);
        myView.invalidate();
    }
    public void show(){
        if (adapter==null||adapter.getCircleCount()==0) {
            return;
        }
        if(anitionFinish){
            anitionFinish=false;
            AnimationSet animationSet=new AnimationSet(true);
            RotateAnimation rotateAnimation = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 1.0f);
            rotateAnimation.setDuration(500);
            rotateAnimation.setAnimationListener(new AnimationListener() {

                @Override
                public void onAnimationStart(Animation animation) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    // TODO Auto-generated method stub
                    anitionFinish=true;
                }
            });
            animationSet.addAnimation(rotateAnimation);
            this.setVisibility(View.VISIBLE);
            this.startAnimation(animationSet);
            this.bringToFront();
        }
    }
    public void dismiss(){
        if (anitionFinish) {
            anitionFinish=false;
            AnimationSet animationSet=new AnimationSet(true);
            RotateAnimation rotateAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 1.0f);
            rotateAnimation.setDuration(800);
            rotateAnimation.setAnimationListener(new AnimationListener() {

                @Override
                public void onAnimationStart(Animation animation) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    // TODO Auto-generated method stub
                    anitionFinish=true;
                    SelectView.this.setVisibility(View.GONE);
                    if (circleNum!=-1) {
                        Map<String, Integer> map=adapter.getSelectMap();                    
                        resultListener.onClickDidFinishAnimationSelectItem(map);
                    }
                }
            });
            animationSet.addAnimation(rotateAnimation);
            this.startAnimation(animationSet);
        }
    }
    private class MyView extends RelativeLayout{

        public MyView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
        }
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub
            if (adapter==null) {
                return false;
            }
            float touchX=event.getX();
            float touchY=event.getY();

            //获取圆心位置
            int originX=getMeasuredWidth()/2;
            int originY=getMeasuredHeight();
            //获取距离圆心距离
            float x=touchX-originX;
            float y=originY-touchY;

            //按下
            super.onTouchEvent(event);
            if (event.getAction()==MotionEvent.ACTION_DOWN) {
                //记录初始位置
                oldX=touchX;
                oldY=touchY;
                double r= Math.sqrt(x*x+y*y);
                if (r>adapter.getOriginWidth()&&r<(adapter.getOriginWidth()+adapter.getRingHeight()*adapter.getCircleCount())) {
                    circleNum=(int) ((r-adapter.getOriginWidth())/adapter.getRingHeight());
                    originTouchPointX=touchX;
                    originTouchPointY=touchY;
                }else {
                    circleNum=-1;
                }
            }
            //手指松开
            if (event.getAction()==MotionEvent.ACTION_UP) {
                if ((touchX-oldX)*(touchX-oldX)+(touchY-oldY)*(touchY-oldY)<200) {
                    if (circleNum!=-1) {
                        List<String> lineDataList=adapter.getDataSource().get(adapter.getKeyList().get(circleNum));
                        //当前圆环的半径
                        double radius=adapter.getOriginWidth()+adapter.getRingHeight()*(circleNum+0.5);
                        //可视角度
                        double visibleAngle=180;
                        if (radius>getMeasuredWidth()/2) {
                            visibleAngle=180-2*Math.acos(getMeasuredWidth()/2.0/radius)*180/Math.PI;
                        }
                        //每个元素的角度
                        double angle=adapter.getTextViewWidth(circleNum)/(Math.PI*radius)*180;
                        if (angle*lineDataList.size()<visibleAngle) {
                            angle=visibleAngle/lineDataList.size();
                        }
                        //                        System.out.println("angle>>>>"+angle);
                        //把x值矫正过来
                        x=-x;
                        double totalAngle=Math.acos(x/Math.sqrt(x*x+y*y))*180/Math.PI-adapter.getAngleWithCircleNum(circleNum)-(180-visibleAngle)/2;
                        //                        System.out.println("totalAngle>>>>"+totalAngle);
                        int selectNum=(int) (totalAngle/angle);
                        //                        System.out.println("selectNum>>>>"+selectNum);
                        if (totalAngle>0&&selectNum<lineDataList.size()) {
                            adapter.setSelectSection(adapter.getKeyList().get(circleNum),Integer.valueOf(selectNum));
                            this.invalidate();
                            if (resultListener!=null) {
                                String key=adapter.getKeyList().get(circleNum);
                                Map<String, Integer> map=adapter.getSelectMap();
                                map.put(key, Integer.valueOf(selectNum));
                            }
                        }
                    }
                    SelectView.this.dismiss();
                }
            }
            //手指移动
            if(event.getAction()==MotionEvent.ACTION_MOVE) {
                if ((touchX-oldX)*(touchX-oldX)+(touchY-oldY)*(touchY-oldY)>=200) {
                if (circleNum!=-1) {
                    //新坐标下的角度
                    double newAngle=Math.acos(x/Math.sqrt(x*x+y*y))*180/Math.PI;
                    //旧坐标下的角度
                    x=originTouchPointX-originX;
                    y=originTouchPointY-originY;
                    double oldAngle=Math.acos(x/Math.sqrt(x*x+y*y))*180/Math.PI;
                    //偏移角度
                    double moveAngle=oldAngle-newAngle;
                    //当前圆环的半径
                    double radius=adapter.getOriginWidth()+adapter.getRingHeight()*(circleNum+0.5);
                    //可视角度
                    double visibleAngle=180;
                    if (radius>getMeasuredWidth()/2) {
                        visibleAngle=180-2*Math.acos(getMeasuredWidth()/2.0/radius)*180/Math.PI;
                    }
                    //点击的位置对应的圆环数据
                    List<String> lineDataList=adapter.getDataSource().get(adapter.getKeyList().get(circleNum));
                    //每个元素的角度
                    double angle=adapter.getTextViewWidth(circleNum)/(Math.PI*radius)*180;
                    if (angle*lineDataList.size()<visibleAngle) {
                        angle=visibleAngle/lineDataList.size();
                    }
                    //                    System.out.println("visibleAngle>>>>"+visibleAngle+">>>>>>angle>>>>>"+angle);
                    //                    System.out.println("moveAngle之前>>>>>>>>"+moveAngle);
                    //向右滑动
                    if (moveAngle>0) {
                        if (moveAngle+adapter.getAngleWithCircleNum(circleNum)>=0) {
                            moveAngle=-adapter.getAngleWithCircleNum(circleNum);
                        }
                    }

                    //向左滑动
                    else if (moveAngle<0){

                        if (visibleAngle-adapter.getAngleWithCircleNum(circleNum)-moveAngle>=angle*lineDataList.size()) {
                            moveAngle=visibleAngle-adapter.getAngleWithCircleNum(circleNum)-angle*lineDataList.size();
                        }
                    }
                    //                    System.out.println("moveAngle之后>>>>>>>>"+moveAngle);
                    adapter.addAngleWithCircleNum(circleNum,Double.valueOf(moveAngle));
                    originTouchPointX=touchX;
                    originTouchPointY=touchY;
                    this.invalidate();
                }    
                }
            }
            //            System.out.println("touch事件");
            return true;
        }

        @SuppressLint("NewApi")
        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);
            //            System.out.println("onDraw>>>事件执行了");
            if (adapter==null) {
                return;
            }
            canvas.translate(getMeasuredWidth()/2, getMeasuredHeight());
            this.drawBackGround(canvas);
            this.drawTextView(canvas);
        }

        private void drawBackGround(Canvas canvas){
            canvas.save();
            int ringHeight=adapter.getRingHeight();
            paint.setStyle(Style.STROKE);
            paint.setStrokeWidth(ringHeight);
            paint.setAntiAlias(true);
            List<Integer> backGroundColors=adapter.getBackGroundColor();
            for (int i = adapter.getCircleCount()-1; i >=0; i--) {    
                paint.setStrokeWidth(ringHeight+1);
                paint.setColor(backGroundColors.get(i).intValue());
                int radius=adapter.getOriginWidth()+ringHeight*i+ringHeight/2;
                RectF rect = new RectF(-radius, -radius, radius, radius);
                canvas.drawArc(rect, 180, 180, false, paint);
            }
            canvas.restore();
        }
        private void drawTextView(Canvas canvas){
            canvas.save();
            paint.setStyle(Style.FILL);
            paint.setStrokeWidth(1.0f);
            paint.setTextSize(adapter.getTextSize());
            int radius=adapter.getOriginWidth()-adapter.getRingHeight()/2;
            for (int i = 0; i < adapter.getKeyList().size(); i++) {
                //获得每一圈的外半径
                radius+=adapter.getRingHeight();
                //每一圈的数据数组
                List<String> lineDataList=adapter.getDataSource().get(adapter.getKeyList().get(i));
                //                System.out.println("lineDataList>>>>>"+lineDataList);
                double visibleAngle=180;
                if (radius>getMeasuredWidth()/2) {
                    visibleAngle=180-2*Math.acos(getMeasuredWidth()/2.0/radius)*180/Math.PI;
                }
                //每个元素的角度
                double angle=adapter.getTextViewWidth(i)/(Math.PI*radius)*180;
                int count=(int) (visibleAngle/angle);
                if (angle*(count+2)<360) {
                    count+=2;
                }else if (angle*(count+1)<360) {
                    count+=1;
                }
                //originNum已经转过了多少个
                int originNum=(int)(-adapter.getAngleWithCircleNum(i)/angle);
                if (originNum<0) {
                    originNum=0;
                }


                //remainCount剩余个数
                int remainCount=lineDataList.size()-originNum;
                if (count>remainCount) {
                    count=remainCount;
                }
                if (angle*adapter.getDataSource().get(adapter.getKeyList().get(i)).size()<visibleAngle) {
                    angle=visibleAngle/adapter.getDataSource().get(adapter.getKeyList().get(i)).size();
                }
                //附加的初始角度
                double extraAngle=adapter.getAngleWithCircleNum(i);
                if (extraAngle<0) {
                    extraAngle=extraAngle%angle;
                }
                //循环填充数据
                for (int j = 0; j < count; j++) {
                    Rect bounds = new Rect();
                    //设置字体颜色
                    if (adapter.getSelectMap().get(adapter.getKeyList().get(i))!=null&&adapter.getSelectMap().get(adapter.getKeyList().get(i)).intValue()==j+originNum) {
                        paint.setColor(adapter.getSelectedTextColor());
                    }else {
                        paint.setColor(adapter.getUnSelectedTextColor(i,j));
                    }
                    paint.getTextBounds(lineDataList.get(j+originNum), 0, lineDataList.get(j+originNum).length(), bounds);
                    int width = bounds.width();
                    int textAngle=(int) (width*180/(Math.PI*radius))+2;
                    int originAngle=(int) (-180+angle*j+(180-visibleAngle)/2+extraAngle+(angle-textAngle)/2);
                    Path path=new Path();
                    RectF rect = new RectF(-radius, -radius, radius, radius);
                    path.addArc(rect, originAngle, textAngle);
                    canvas.drawTextOnPath(lineDataList.get(j+originNum), path, 0, adapter.getTextSize()/2, paint);
                }
            }
            canvas.restore();
        }
    }

    public void setSelectViewResultListener(SelectViewResultListener listener){
        resultListener=listener;
    }
    static public interface SelectViewResultListener{
        public void onClickDidFinishAnimationSelectItem(Map<String, Integer> map);
    }
    static abstract public class SelectViewAdapter {
        protected Context mContext;
        private Map<Integer, Double> angleMap;
        private  Map<String, Integer> mySelectMap;
        private SelectView serviceView;
        public SelectViewAdapter(Context context) {
            // TODO Auto-generated constructor stub
            mContext=context;
            mySelectMap=setSelectMap();
        }
        //把dataSource从内到外的key按顺序放入list中,内容不能为空
        abstract public List<String> getKeyList();
        /*
         * getDataSource与getSelectMap键相同
         */
        //提供的选项
        abstract public Map<String, List<String>> getDataSource();
        //定义选中的map
        abstract public Map<String, Integer> setSelectMap();
        //设置选中的map
        public Map<String, Integer> getSelectMap(){
            if (mySelectMap==null) {
                mySelectMap=new HashMap<String, Integer>();
                for (int i = 0; i < getCircleCount(); i++) {
                    mySelectMap.put(getKeyList().get(i), Integer.valueOf(0));
                }
            }
            return mySelectMap;
        }
        public void setServiceView(SelectView view){
            serviceView=view;
        }
        //设置选中的选项
        public void setSelectSection(String key,Integer num){
            mySelectMap.put(key, num);
        }
        //每个环转过的角度
        @SuppressLint("UseSparseArrays")
        public void addAngleWithCircleNum(int circleNum,Double angle){
            if (angleMap==null) {
                angleMap=new HashMap<Integer, Double>();
                for (int i = 0; i < getCircleCount(); i++) {
                    angleMap.put(Integer.valueOf(i), Double.valueOf(0));
                }
            }
            angleMap.put(Integer.valueOf(circleNum), angleMap.get(Integer.valueOf(circleNum))+angle);
        }
        public double getAngleWithCircleNum(int circleNum){
            double angle=0;
            if (angleMap!=null) {
                angle=angleMap.get(Integer.valueOf(circleNum)).doubleValue();
            }
            return angle;
        }
        //设置选中的选项字体颜色
        public int getSelectedTextColor(){return Color.RED;}
        //设置未选中的选项字体颜色
        public int getUnSelectedTextColor(int circleNum,int columns){return Color.WHITE;}
        //设置字体大小
        public float getTextSize(){
            return getRingHeight()/3;
        }
        //设置每个选项的宽度
        public int getTextViewWidth(int circleNum){
            int width=1;
            if (getDataSource()!=null) {
                Paint paint =new Paint();
                paint.setTextSize(getTextSize());
                Rect bounds = new Rect();

                List<String> lineDataList=getDataSource().get(getKeyList().get(circleNum));
                for (String string : lineDataList) {
                    paint.getTextBounds(string, 0, string.length(), bounds);
                    if (width<bounds.width()) {
                        width=bounds.width();
                    }
                }
            }
            return width+30;
        }
        //设置最内层圆环的内边缘初始半径
        public int getOriginWidth(){
            int radius=0;
            if (serviceView!=null) {
                if (serviceView.getMeasuredWidth()>serviceView.getMeasuredHeight()) {
                    radius=serviceView.getMeasuredHeight()/4;
                }else {
                    radius=serviceView.getMeasuredWidth()/4;
                }
                
            }else {
                DisplayMetrics metric = new DisplayMetrics();
                ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(metric);
                radius=metric.widthPixels/4;
            }
            return radius;
        }
        //设置每个圆环的高度
        public int getRingHeight(){
            int ringHeight=0;
            if (serviceView!=null) {
                if (serviceView.getMeasuredWidth()>serviceView.getMeasuredHeight()) {
                    ringHeight=serviceView.getMeasuredHeight()/9;
                }else {
                    ringHeight=serviceView.getMeasuredWidth()/9;
                }
                
            }else {
                DisplayMetrics metric = new DisplayMetrics();
                ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(metric);
                ringHeight=metric.widthPixels/9;
            }

            return ringHeight;
        }
        public int getCircleCount(){
            int count=0;
            if (getDataSource()!=null) {
                count=getDataSource().size();
            }
            return count;
        }
        //返回的色值是integer类型的list
        public List<Integer> getBackGroundColor(){
            List<Integer> colorList=new ArrayList<Integer>();
            //UIColorFromRGB(0xfdd1ae),UIColorFromRGB(0xfdba86),UIColorFromRGB(0xffa45e),UIColorFromRGB(0xfe8c36),UIColorFromRGB(0xfe8c36),UIColorFromRGB(0xfe8c36)
            colorList.add(Integer.valueOf(0xfffdd1ae));
            colorList.add(Integer.valueOf(0xFFfdba86));
            colorList.add(Integer.valueOf(0xFFffa45e));
            colorList.add(Integer.valueOf(0xFFfe8c36));
            colorList.add(Integer.valueOf(0xFFfe8c36));
            colorList.add(Integer.valueOf(0xFFfe8c36));
            colorList.add(Integer.valueOf(0xFFEB8E55));
            colorList.add(Integer.valueOf(0xFF708069));
            colorList.add(Integer.valueOf(0xFFFAEBD7));
            colorList.add(Integer.valueOf(0xFF7FFFD4));
            colorList.add(Integer.valueOf(0xFFB0E0E6));
            colorList.add(Integer.valueOf(0xFFB0171F));
            colorList.add(Integer.valueOf(0xFFFF00FF));
            return colorList;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值