Android 获取全国城市列表类似于联系人排序(二)

介绍了一种基于Android的补充工具栏,具备精美的动画效果,能够实现字母快速检索列表信息,如城市列表效果。通过简单的依赖添加和监听设置,即可在应用中实现这一功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于Android的补充工具栏,具有精美的动画效果,实现字母快速检索列表信息类似城市列表效果。

一.效果图:

 

二.添加依赖方式快速实现:

1.添加依赖:

dependencies {
	       implementation 'com.github.AlexLiuSheng:AnimSideBar:1.0.0'
	}

2.布局:

  <com.allenliu.sidebar.SideBar
    android:layout_alignParentRight="true"
    android:textColor="@color/colorAccent"
    android:textSize="12sp"
    android:paddingRight="10dp"
    android:layout_width="wrap_content"
    android:id="@+id/bar"
    android:layout_height="match_parent" />

3.监听:

bar.setOnStrSelectCallBack(new ISideBarSelectCallBack() {
        @Override
        public void onSelectStr(int index, String selectStr) {
            Toast.makeText(SideBarDemoActivity.this,selectStr,Toast.LENGTH_SHORT).show();
        }
    });

三.自定义快速实现:

1.主函数代码:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.allenliu.sidebar.ISideBarSelectCallBack;
import com.allenliu.sidebar.SideBar;


public class SideBarDemoActivity extends AppCompatActivity {
 private SideBar bar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bar= (SideBar) findViewById(R.id.bar);
        bar.setOnStrSelectCallBack(new ISideBarSelectCallBack() {
            @Override
            public void onSelectStr(int index, String selectStr) {
          //      Toast.makeText(SideBarDemoActivity.this,selectStr,Toast.LENGTH_SHORT).show();
            }
        });
    }
}

2.布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:sidebar="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".SideBarDemoActivity">

    <com.ceshi.sidebar.SideBar
        android:id="@+id/bar"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:paddingRight="10dp"
        android:textColor="@color/colorAccent"
        android:textSize="12sp" />

</RelativeLayout>

3.自定义SideBar.java

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;

/**
 * 自定义SideBar
 */
public class SideBar extends android.support.v7.widget.AppCompatTextView {
    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 Paint textPaint;
    private Paint bigTextPaint;

    private ISideBarSelectCallBack callBack;
    private float eventY;
    private float w;
    private float sideTextWidth;
    /**
     * 是否重新测量宽高
     */
    private boolean isTouching = false;
    private float itemH;

    /**
     * 振幅
     */
    private float A = dp(100);
    /**
     * 波峰与bigText之间的距离
     */
    private int gapBetweenText = dp(50);

    /**
     * 开口数量
     */
    private int openCount = 13;
    /**
     * 字体缩放,基于textSize
     */
    private float fontScale = 1;
    private float bigTextSize;

    public SideBar(Context context) {
        super(context);
        init(null);
    }

    public SideBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public SideBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    /**
     * set MaxFontScale
     *
     * @param fontScale
     * @return
     */
    public SideBar setFontScale(float fontScale) {
        this.fontScale = fontScale;
        return this;
    }

    public void setDataResource(String[] data) {
        letters = data;
        invalidate();
    }

    public void setOnStrSelectCallBack(ISideBarSelectCallBack callBack) {
        this.callBack = callBack;
    }

    public SideBar setBigTextSize(float bigTextSize) {
        this.bigTextSize = bigTextSize;
        bigTextPaint.setTextSize(bigTextSize);
//        invalidate();
        return this;
    }

    public SideBar setA(float a) {
        A = a;
//        invalidate();
        return this;
    }

    public SideBar setGapBetweenText(int gapBetweenText) {
        this.gapBetweenText = gapBetweenText;
//        invalidate();
        return this;
    }

    public SideBar setOpenCount(int openCount) {
        this.openCount = openCount;
//        invalidate();
        return this;
    }

    private void caculateAW(int height) {
        itemH = height * 1.0f / letters.length;
        /**
         * 开口宽度
         */
        float opendWidth = itemH * openCount;
        //角速度 2PI/t 周期
        w = (float) (Math.PI * 2.0f / (opendWidth * 2));
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int mode = MeasureSpec.getMode(widthMeasureSpec);
        int viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        caculateAW(MeasureSpec.getSize(heightMeasureSpec));
        if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
            viewWidth = !isTouching ? (int) (sideTextWidth + getPaddingLeft() + getPaddingRight()) : (int) (A + gapBetweenText + getBigTextWidth() + getPaddingLeft() + getPaddingRight());
        }
//        CLog.e("width:" + viewWidth + "height:" + MeasureSpec.getSize(heightMeasureSpec));
        setMeasuredDimension(viewWidth, MeasureSpec.getSize(heightMeasureSpec));
    }

    private void init(AttributeSet attrs) {
        //  setPadding(dp(10), 0, dp(10), 0);
        if (attrs != null) {
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.SideBar);
            A = typedArray.getInteger(R.styleable.SideBar_A, dp(100));
            fontScale = typedArray.getFloat(R.styleable.SideBar_fontScale, 1);
            bigTextSize = typedArray.getFloat(R.styleable.SideBar_bigTextSize, getTextSize() * 3);
            gapBetweenText = typedArray.getInteger(R.styleable.SideBar_gapBetweenText, dp(50));
            openCount = typedArray.getInteger(R.styleable.SideBar_openCount, 13);
        } else {
            bigTextSize = getTextSize() * 3;
        }
        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setColor(getCurrentTextColor());
        textPaint.setTextSize(getTextSize());
        textPaint.setTextAlign(Paint.Align.CENTER);

        bigTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bigTextPaint.setColor(getCurrentTextColor());
        bigTextPaint.setTextSize(bigTextSize);
        bigTextPaint.setTextAlign(Paint.Align.CENTER);


        float sideTextHeight = textPaint.getFontMetrics().descent - textPaint.getFontMetrics().ascent;
        sideTextWidth = textPaint.measureText("W");
    }


    private int dp(int v) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (v * scale + 0.5f);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int startTouchX = (int) (getMeasuredWidth() - A);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                if (event.getX() > startTouchX) {
                    eventY = event.getY();
                    if (!isTouching) {
                        isTouching = true;
                        requestLayout();
                    } else {
                        invalidate();
                    }

                } else {
                    if (isTouching) {
                        resetDefault();
                    }
                }
                return true;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                resetDefault();
                return true;

        }
        return super.onTouchEvent(event);
    }

    private void resetDefault() {
        isTouching = false;
        eventY = 0;
        requestLayout();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        int singleSideCount = openCount / 2;
        int index = isTouching && eventY >= 0 && eventY <= getMeasuredHeight() ? (int) Math.floor((eventY / itemH)) : -(singleSideCount + 1);
//        index=Math.min(letters.length,index);
//        CLog.e("index:" + index + "eventY:" + eventY);
        float sideX = sideTextWidth / 2 + getPaddingRight();
        for (int i = 0; i < letters.length; i++) {
            //rest textsize
            textPaint.setTextSize(getTextSize());
            int y = (int) (itemH * (i + 1));
            int x;
            if (Math.abs(i - index) > singleSideCount) {
                x = (int) (getMeasuredWidth() - sideX);
            } else {
                float percent = eventY / itemH;
                int t = (int) (i * itemH - eventY);
                double v = A * Math.sin(w * t + Math.PI / 2);

//                //如果算出来小于字体宽度 就取字体宽度
                v = Math.max(v, sideX);
                x = (int) (getMeasuredWidth() - v);
                //根据delta缩放字体
                if (v == sideX) {
                    textPaint.setTextSize(getTextSize());
                } else {
                    float delta = (Math.abs((i - percent)) / singleSideCount);
                    float textSize = getTextSize() + (1 - delta) * getTextSize() * fontScale;
//                    textSize=Math.max(textSize,getTextSize());
                    textPaint.setTextSize(textSize);
                }

            }
            canvas.drawText(letters[i], x, y, textPaint);

        }
        if (index != -(singleSideCount + 1)) {
            canvas.drawText(letters[index], getPaddingLeft() + getBigTextWidth() / 2, (int) (itemH * (index + 1)), bigTextPaint);
            if (callBack != null) {
                callBack.onSelectStr(index, letters[index]);

            }
        }

    }

    private float getBigTextWidth() {
        return bigTextPaint.measureText("W");
    }
}

4.定义接口:


/**
 * 定义接口
 */
public interface ISideBarSelectCallBack {
     void onSelectStr(int index,String selectStr);
}

5.attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SideBar">
        <attr name="fontScale" format="float" />
        <attr name="bigTextSize" format="float" />
        <attr name="openCount" format="integer" />
        <attr name="A" format="integer" />
        <attr name="gapBetweenText" format="integer" />

    </declare-styleable>
</resources>

其它案例:

https://github.com/weixueandroid/CitySelectorDemo

https://github.com/AlexLiuSheng/AnimSideBar

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值