Android A-Z通讯录,点击弧度效果,椭圆效果

动画效果 同时被 2 个专栏收录
12 篇文章 0 订阅
4 篇文章 0 订阅

转载请注明出处,谢谢http://blog.csdn.net/harryweasley/article/details/55253489

开始本篇博客之前,先看下效果,效果如下所示
这里写图片描述

本控件主要有两个难点:
第一个是最上面的那个放大镜的字符符号效果。
第二个是点击A-Z成为一个弧度,我在此用的是正弦函数曲线。

还是先放一个固定图片,否则看不清ui设计,如下所示:
这里写图片描述

关于放大镜的那个字符符号,我用的iconfont里面制作好的,直接将其作为一个String来放入数组中。关于怎么使用该字符符号,你可以查看该网址,http://www.iconfont.cn/plus/help/detail?helptype=code&spm=a313x.7781069.1998910419.14.SMz5js

官方文档有一些问题,我这里说一下,下载下来,点开demo_unicode.html文件,即可看到码值

如下图所示:

这里写图片描述

这里写图片描述

这里必须要说:字符符号必须放入string.xml中,以getResources().getString(id)来得到。

现在来说明,正弦函数曲线,如下图所示:
这里写图片描述

我们只需要0—π的曲线,最高点是弧度π/2,假设L点是最高点,那么L的角度是90,其他角度分别分别为
M-72, N-54, O-36, P-18, Q-0,
K-108, J-126, I-144, H-162, G-180

计算出点击状态,view的高度,即L所处的横向高度maxHeight,然后通过该方法,则得到每个点的x值

x = (float) (maxHeight * (1 - Math.sin(arc * Math.PI / 180)))

这里说明一点,其实在此情况下,L值的x值为0,G和Q的x值才为maxHeight,因为view的x值是从左到右的。

剩下的细节,大家就自己看代码吧。

package com.example.lgx.mycontactdemo;

/**
 * Created by Harry on 2017-1-3.
 */

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
import android.widget.TextView;


/**
 * @author Harry
 */
public class ContactRightView extends TextView {

//    private String[] letters = new String[]{
//            "✈", "A", "B", "C", "D", "E",
//            "F", "G", "H", "I", "J", "K",
//            "L", "M", "N", "O", "P", "Q",
//            "R", "S", "T", "U", "V", "W",
//            "X", "Y", "Z","#"};


    private String[] letters = new String[]{
            "", "A", "B", "C", "D", "E",
            "F", "G", "H", "I", "J", "K",
            "L", "M", "N", "O", "P", "Q",
            "R", "S", "T", "U", "V", "W",
            "X", "Y", "Z", "#"};

    /**
     * 每一个字母的高度
     */
    private int singleHeight;
    /**
     * 控件的高度
     */
    private int height;
    private float arc = 0;
    /**
     * 最高的高度
     */
    private float maxHeight;

    private float normalWidth;
    private float selectedWidth;
    /**
     * 是否是选择状态,默认为false
     */
    private boolean iSelectedState = false;

    private float textSize;

    private int startPos = -1;
    private int endPos = -1;
    private float measureTextSize = -1;
    /**
     * 接口变量,该接口主要用来实现当手指在右边的滑动控件上滑动时ListView能够跟着滚动
     */
    private UpdateListView updateListView;
    Typeface plain;
    String test;
    private Context context;

    public ContactRightView(Context context) {
        this(context, null);
    }

    public ContactRightView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ContactRightView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context=context;
        plain = Typeface.createFromAsset(context.getAssets(), "iconfont.ttf");
        test = context.getResources().getString(R.string.test);
        init();
    }

    private void init() {
        textSize = 14;
        normalWidth = getResources().getDimensionPixelSize(R.dimen.normal_width);
        selectedWidth = getResources().getDimensionPixelSize(R.dimen.selected_width);
        maxHeight = selectedWidth-getResources().getDimension(R.dimen.activity_vertical_margin);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float y = event.getY();
        int oldChoose = choose;

        int selectIndex = (int) (y / (height / letters.length));
        if (selectIndex > -1 && selectIndex < letters.length) {
            String key = letters[selectIndex];
            if (updateListView != null) {
                updateListView.updateListView(key);
            }
            if (!iSelectedState) {
                iSelectedState = true;
                setLayoutParams((int) selectedWidth);
            }
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (oldChoose != selectIndex) {
                    if (selectIndex >= 0 && selectIndex < letters.length) {
                        choose = selectIndex;
                        invalidate();
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (oldChoose != selectIndex) {
                    if (selectIndex > -1 && selectIndex < letters.length) {
                        choose = selectIndex;
                        invalidate();
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                resetView();
                break;
            case MotionEvent.ACTION_CANCEL:
                resetView();
                break;
            default:
                break;
        }

        return true;
    }


    private void resetView() {
        choose = -1;
        iSelectedState = false;
        setLayoutParams((int) normalWidth);
    }


    private void setLayoutParams(int width) {
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(width,
                RelativeLayout.LayoutParams.MATCH_PARENT);
        lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        setLayoutParams(lp);
    }

    Paint paint = new Paint();
    /**
     * 当前选中的位置
     */
    int choose = -1;


    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        height = getHeight();
        singleHeight = height / letters.length;
        getStartAndEndPosFromArg();

        for (int i = 0; i < letters.length; i++) {
            paint.setColor(ContextCompat.getColor(context,R.color.blue2));
            setPaintSize(textSize);
            Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
            paint.setTypeface(font);
            paint.setAntiAlias(true);
            if(i==0){
                measureTextSize = paint.measureText(letters[1]);
            }else{
                measureTextSize = paint.measureText(letters[i]);
            }
            float xPos, yPos;
            if (iSelectedState) {
                //如果选中状态,所有的字母的x数值会比没选中之前变大
                xPos = selectedWidth - normalWidth / 2 - measureTextSize / 2;
            } else {
                xPos = normalWidth / 2 - measureTextSize / 2;
            }

            yPos = singleHeight * i + singleHeight;

            if (i == choose) {
                paint.setFakeBoldText(true);
            }

            if ((i >= startPos && i <= endPos) && choose != -1 && iSelectedState) {
                getArcFromCurrentPos(i);
                xPos = getXFormArg();
                float size = getLetterTextSize(i);
                setPaintSize(size);
            }
            if (i == 0) {
                paint.setTypeface(plain);
                canvas.drawText(test, xPos - 3, yPos, paint);
            } else {
                canvas.drawText(letters[i], xPos, yPos, paint);
            }

            paint.reset();
        }
    }

    private void setPaintSize(float size) {
        float realSize = TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, size, getResources().getDisplayMetrics());
        if (realSize != paint.getTextSize()) {
            paint.setTextSize(realSize);
        }

    }


    /**
     * 由当前位置获取角度
     */
    private void getArcFromCurrentPos(int i) {
        int value = i - choose;
        if (value == 0) {
            arc = 90;
        } else {
            arc = 90 - value * 18;
        }
        if (Math.abs(value) == 1) {
            paint.setAlpha(77);
        } else if (Math.abs(value) == 2) {
            paint.setAlpha(128);
        } else if (Math.abs(value) == 3) {
            paint.setAlpha(153);
        } else if (Math.abs(value) == 4) {
            paint.setAlpha(204);
        }
    }

    /**
     * 得到开始绘图位置和结束绘图位置
     */
    private void getStartAndEndPosFromArg() {
        if (choose != -1) {
            if (choose <= 4) {
                startPos = 0;
            } else {
                startPos = choose - 4;
            }
            if (choose - letters.length + 5 <= 0) {
                endPos = choose + 4;
            } else {
                endPos = letters.length - 1;
            }
        }
    }

    /**
     * 不同位置的字母不同的字体大小
     * @param i
     * @return
     */
    private float getLetterTextSize(int i) {
        textSize = 14;
        if (i == choose) {
            return textSize + 18;
        } else if (i + 1 == choose || choose + 1 == i) {
            return textSize + 14;
        } else if (i + 2 == choose || choose + 2 == i) {
            return textSize + 10;
        } else if (i + 3 == choose || choose + 3 == i) {
            return textSize + 4;
        }
        return textSize;
    }


    /**
     * 由当前的角度得到x值
     * @return
     */
    private float getXFormArg() {
        float x = (float) (maxHeight * (1 - Math.sin(arc * Math.PI / 180)));
        return x;
    }

    public void setUpdateListView(UpdateListView updateListView) {
        this.updateListView = updateListView;
    }

    public interface UpdateListView {
        void updateListView(String currentChar);
    }

}

string.xml的内容如下所示:

<resources>
    <string name="app_name">MyContactDemo</string>
    <string name="test">&#xe634;</string>
</resources>

源码下载地址:https://github.com/HarryWeasley/ContactDemo

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值