作者:xinzhugedonny | 来源:互联网 | 2024-12-19 13:14
在许多地理位置选择类的应用程序中,侧边栏是常见的用户界面元素,用于通过选择特定的字母快速定位和选择地点。本文将详细介绍如何在Android应用中创建一个具有波浪效果的自定义侧边栏,以提升用户体验。
在众多地理位置选择应用程序中,侧边栏作为一个重要的UI组件,允许用户通过选择首字母快速跳转至特定地名,极大地提高了选择效率。本文将引导你构建一个具有独特波浪视觉效果的自定义侧边栏,为你的应用增添一抹亮色。
为了实现这一功能,我们需要使用Android的自定义视图技术,结合图形绘制和动画效果,具体代码如下:
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.Arrays;
import java.util.List;
public class CustomWaveSideBarView extends View {
private static final String TAG = "WaveSlideBarView";
// 计算波浪贝塞尔曲线的角弧长值
private float mAngle;
private Paint mPaint;
private Path mPath;
private List mLetters;
private int mHeight;
private int mWidth;
private float mLetterSize;
private float mLetterSpacing;
private int mSelectedIndex;
private OnLetterChangedListener mListener;
public CustomWaveSideBarView(Context context) {
this(context, null);
}
public CustomWaveSideBarView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomWaveSideBarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
mPaint.setTextSize(dp2px(14));
mPath = new Path();
mLetters = Arrays.asList("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");
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mHeight = h;
mWidth = w;
mLetterSize = (mHeight - mLetterSpacing * (mLetters.size() - 1)) / mLetters.size();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawWave(canvas);
drawLetters(canvas);
}
private void drawWave(Canvas canvas) {
mPath.reset();
mPath.moveTo(0, 0);
for (int i = 0; i float y = i * (mLetterSize + mLetterSpacing) + mLetterSize / 2;
float x = (float) (mWidth * Math.sin(mAngle * i));
if (i == 0) {
mPath.lineTo(x, y);
} else {
mPath.quadTo(x / 2, y - mLetterSize / 2, x, y);
}
}
mPath.lineTo(mWidth, mHeight);
mPath.lineTo(0, mHeight);
mPath.close();
canvas.drawPath(mPath, mPaint);
}
private void drawLetters(Canvas canvas) {
for (int i = 0; i String letter = mLetters.get(i);
float y = i * (mLetterSize + mLetterSpacing) + mLetterSize;
canvas.drawText(letter, 0, y, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
float y = event.getY();
mSelectedIndex = (int) (y / (mLetterSize + mLetterSpacing));
if (mSelectedIndex >= 0 && mSelectedIndex if (mListener != null) {
mListener.onLetterChanged(mLetters.get(mSelectedIndex));
}
}
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
public void setOnLetterChangedListener(OnLetterChangedListener listener) {
this.mListener = listener;
}
public interface OnLetterChangedListener {
void onLetterChanged(String letter);
}
private int dp2px(float dpValue) {
final float scale = getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}