先来句古德莫宁
26字母导航条很早就有了,比如微信的联系人列表,比如网易云搜索音乐的列表都有。不过我不怎么喜欢这个设计感觉有点老。不过项目需求需要还是自己手撸了一个,思路也很简单,唯一的麻烦就知识判断坐标而已,但如果你看过事件分发源码这个也是很好理解。
先上代码:
public class XzPyNavigationBar extends LinearLayout {
private Context context;
//数据源
private String[] arr = {"◉", "热", "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 AttachPopup attachPopup;
private OnChangeNavigation onChangeNavigation;
private int LightIndex = 1; //高亮下标 默认为1
public XzPyNavigationBar(Context context) {
this(context, null);
}
public XzPyNavigationBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setOrientation(VERTICAL);
//设置一下导航条的背景色美化下导航条
setBackgroundResource(R.drawable.xz_py_navigation_back);
setPadding(10, 20, 10, 40);
if (this.context == null) {
this.context = context;
}
initView();
addListener();
}
//设置选中的元素,根据下标设置
public void setLightIndex(int lightIndex) {
LightIndex = lightIndex;
for (int i = 0; i < getChildCount(); i++) {
if (i == this.LightIndex) {
((TextView) getChildAt(i)).setTextColor(Color.parseColor("#F9BD00"));
} else {
((TextView) getChildAt(i)).setTextColor(Color.parseColor("#C5C5C5"));
}
}
}
//设置选中的元素,根据内容设置
public void setLightIndex(String v) {
for (int i = 0; i < arr.length; i++) {
if (v.equals(arr[i])) {
setLightIndex(i);
break;
}
}
}
private void initView() {
for (int i = 0; i < arr.length; i++) {
final TextView textView = (TextView) LayoutInflater.from(context).inflate(R.layout.xz_py_navigation_item, null);
textView.setText(arr[i]);
if (i == LightIndex) textView.setTextColor(Color.parseColor("#F9BD00"));
addView(textView);
}
}
//默认拦截为true
//这里必须这样做
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
private void addListener() {
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
for (int i = 1; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setTextColor(Color.parseColor("#C5C5C5"));
if (isTouchPointInView(getChildAt(i), (int) event.getRawX(), (int) event.getRawY())) {
popwin((TextView) getChildAt(i), ((TextView) getChildAt(i)).getText().toString());
((TextView) getChildAt(i)).setTextColor(Color.parseColor("#F9BD00"));
if (onChangeNavigation != null)
onChangeNavigation.Chanage(((TextView) getChildAt(i)).getText().toString());
}
}
break;
case MotionEvent.ACTION_MOVE:
for (int i = 1; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setTextColor(Color.parseColor("#C5C5C5"));
if (isTouchPointInView(getChildAt(i), (int) event.getRawX(), (int) event.getRawY())) {
if (attachPopup != null) {
attachPopup.UploadText(((TextView) getChildAt(i)).getText().toString());
((TextView) getChildAt(i)).setTextColor(Color.parseColor("#F9BD00"));
if (onChangeNavigation != null)
onChangeNavigation.Chanage(((TextView) getChildAt(i)).getText().toString());
}
}
}
break;
case MotionEvent.ACTION_UP:
if (attachPopup != null) attachPopup.dismiss();
break;
}
return true;
}
});
}
//震动效果
private void zd() {
Vibrator vibrator = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE);
vibrator.vibrate(10);
}
//判断坐标在哪个子元素范围
private boolean isTouchPointInView(View view, int x, int y) {
if (view == null) {
return false;
}
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
if (y >= top && y <= bottom) {
return true;
}
return false;
}
//弹窗
private void popwin(TextView t, String s) {
attachPopup = new AttachPopup(context, s);
attachPopup.setBackgroundColor(Color.TRANSPARENT);
attachPopup.showPopupWindow();
}
//弹窗内部类
//三方控件 implementation 'com.github.razerdp:BasePopup:2.2.1'
public class AttachPopup extends BasePopupWindow {
private TextView textView;
public void UploadText(String s) {
if (!textView.getText().equals(s)) {
zd();
textView.setText(s);
}
}
public AttachPopup(Context context, String s) {
super(context);
textView = findViewById(R.id.tv_desc);
textView.setText(s);
}
@Override
protected Animation onCreateShowAnimation() {
return null;
}
@Override
protected Animation onCreateDismissAnimation() {
return null;
}
@Override
public View onCreateContentView() {
return createPopupById(R.layout.xz_py_navigation_pop);
}
}
//移动改变回调方法
public void setOnChangeNavigation(OnChangeNavigation onChangeNavigation) {
this.onChangeNavigation = onChangeNavigation;
}
public interface OnChangeNavigation {
void Chanage(String value);
}
}
思路:继承已个线性布局,设置为VERTICAL,这样就省的你自己去布局了,然后直接addview进去Textview。当然这里的TextVIew你需要根据你的数据源去动态添加一下。然后就是重写一下拦截方法,直接改为true,就是只要到了它导航条这里,就默认自己处理了,这样的目的是为了你手指离开导航的时候还能随意滑动。那么怎么判断呢,这里判断我门只判断y坐标。判断当前的y坐标在哪个textview的范围内,就亮哪个。
判断坐标方法:
private boolean isTouchPointInView(View view, int x, int y) {
if (view == null) {
return false;
}
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
//只判断上下
if (y >= top && y <= bottom) {
return true;
}
return false;
}
ok,搞定收工。困死了。