setContentView(R.layout.main);
// 初始化一些数据
mItems = new ArrayList();
mItems.add(“Diary of a Wimpy Kid 6: Cabin Fever”);
mItems.add(“Steve Jobs”);
mItems.add(“Inheritance (The Inheritance Cycle)”);
mItems.add(“11/22/63: A Novel”);
mItems.add(“The Hunger Games”);
mItems.add(“The LEGO Ideas Book”);
mItems.add(“Explosive Eighteen: A Stephanie Plum Novel”);
mItems.add(“Catching Fire (The Second Book of the Hunger Games)”);
mItems.add(“Elder Scrolls V: Skyrim: Prima Official Game Guide”);
mItems.add(“Death Comes to Pemberley”);
mItems.add(“Diary of a Wimpy Kid 6: Cabin Fever”);
mItems.add(“Steve Jobs”);
mItems.add(“Inheritance (The Inheritance Cycle)”);
mItems.add(“11/22/63: A Novel”);
mItems.add(“The Hunger Games”);
mItems.add(“The LEGO Ideas Book”);
mItems.add(“Explosive Eighteen: A Stephanie Plum Novel”);
mItems.add(“Catching Fire (The Second Book of the Hunger Games)”);
mItems.add(“Elder Scrolls V: Skyrim: Prima Official Game Guide”);
mItems.add(“做作”);
mItems.add(“wokao”);
Collections.sort(mItems); // 排序
ContentAdapter adapter = new ContentAdapter(this,
android.R.layout.simple_list_item_1, mItems);
mListView = (IndexableListView) findViewById(R.id.listview);
mListView.setAdapter(adapter);
mListView.setFastScrollEnabled(true); // 设置快速滑动
}
private class ContentAdapter extends ArrayAdapter implements
SectionIndexer {
private String mSections = “#ABCDEFGHIJKLMNOPQRSTUVWXYZ”;
public ContentAdapter(Context context, int textViewResourceId,
List objects) {
super(context, textViewResourceId, objects);
}
@Override
public int getPositionForSection(int section) {
// If there is no item for current section, previous section will be
// selected
// 如果当前部分没有item,则之前的部分将被选择
for (int i = section; i >= 0; i–) {
for (int j = 0; j < getCount(); j++) {
System.out.println(getCount());
if (i == 0) { // #
// For numeric section 数字
for (int k = 0; k <= 9; k++) {// 1…9
// 字符串第一个字符与1~9之间的数字进行匹配
if (StringMatcher.match(
String.valueOf(getItem(j).charAt(0)),
String.valueOf(k)))
return j;
}
} else { // A~Z
if (StringMatcher.match(
String.valueOf(getItem(j).charAt(0)),
String.valueOf(mSections.charAt(i))))
return j;
}
}
}
return 0;
}
@Override
public int getSectionForPosition(int position) {
return 0;
}
@Override
public Object[] getSections() {
String[] sections = new String[mSections.length()];
for (int i = 0; i < mSections.length(); i++)
sections[i] = String.valueOf(mSections.charAt(i));
return sections;
}
}
}
字符串匹配工具类
/*
-
Copyright 2011 woozzu
-
Licensed under the Apache License, Version 2.0 (the “License”);
-
you may not use this file except in compliance with the License.
-
You may obtain a copy of the License at
-
http://www.apache.org/licenses/LICENSE-2.0
-
Unless required by applicable law or agreed to in writing, software
-
distributed under the License is distributed on an “AS IS” BASIS,
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-
See the License for the specific language governing permissions and
-
limitations under the License.
*/
package com.wwj.indexableListView.util;
public class StringMatcher {
// 这些变量是韩文,小巫也不知道是什么意思,有谁懂的马上联系我啊
private final static char KOREAN_UNICODE_START = ‘가’; // 韩文字符编码开始?
private final static char KOREAN_UNICODE_END = ‘힣’; // 韩文字符编码结束?
private final static char KOREAN_UNIT = ‘까’ - ‘가’; // 不知道是啥?
// 韩文的一些字符初始化
private final static char[] KOREAN_INITIAL = { ‘ㄱ’, ‘ㄲ’, ‘ㄴ’, ‘ㄷ’, ‘ㄸ’,
‘ㄹ’, ‘ㅁ’, ‘ㅂ’, ‘ㅃ’, ‘ㅅ’, ‘ㅆ’, ‘ㅇ’, ‘ㅈ’, ‘ㅉ’, ‘ㅊ’, ‘ㅋ’, ‘ㅌ’, ‘ㅍ’,
‘ㅎ’ };
/**
-
字符匹配
-
@param value 需要keyword匹配的字符串
-
@param keyword #ABCDEFGHIJKLMNOPQRSTUVWXYZ中的一个
-
@return
*/
public static boolean match(String value, String keyword) {
if (value == null || keyword == null)
return false;
if (keyword.length() > value.length())
return false;
int i = 0, j = 0;
do {
// 如果是韩文字符并且在韩文初始数组里面
if (isKorean(value.charAt(i)) && isInitialSound(keyword.charAt(j))) {
if (keyword.charAt(j) == getInitialSound(value.charAt(i))) {
i++;
j++;
} else if (j > 0)
break;
else
i++;
} else {
// 逐个字符匹配
if (keyword.charAt(j) == value.charAt(i)) {
i++;
j++;
} else if (j > 0)
break;
else
i++;
}
} while (i < value.length() && j < keyword.length());
// 如果最后j等于keyword的长度说明匹配成功
return (j == keyword.length()) ? true : false;
}
// 判断字符是否在韩文字符编码范围内
private static boolean isKorean(char c) {
if (c >= KOREAN_UNICODE_START && c <= KOREAN_UNICODE_END)
return true;
return false;
}
// 判断是否在韩文字符里面
private static boolean isInitialSound(char c) {
for (char i : KOREAN_INITIAL) {
if (c == i)
return true;
}
return false;
}
// 获得韩文初始化字符数组里面的一个字符
private static char getInitialSound(char c) {
return KOREAN_INITIAL[(c - KOREAN_UNICODE_START) / KOREAN_UNIT];
}
}
自定义索引列表
/*
-
Copyright 2011 woozzu
-
Licensed under the Apache License, Version 2.0 (the “License”);
-
you may not use this file except in compliance with the License.
-
You may obtain a copy of the License at
-
http://www.apache.org/licenses/LICENSE-2.0
-
Unless required by applicable law or agreed to in writing, software
-
distributed under the License is distributed on an “AS IS” BASIS,
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-
See the License for the specific language governing permissions and
-
limitations under the License.
*/
package com.wwj.indexableListView.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ListAdapter;
import android.widget.ListView;
/**
-
自定义索引列表
-
@author by 佚名
*/
public class IndexableListView extends ListView {
private boolean mIsFastScrollEnabled = false;
private IndexScroller mScroller = null;
private GestureDetector mGestureDetector = null;
public IndexableListView(Context context) {
super(context);
}
public IndexableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public IndexableListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean isFastScrollEnabled() {
return mIsFastScrollEnabled;
}
@Override
public void setFastScrollEnabled(boolean enabled) {
mIsFastScrollEnabled = enabled;
if (mIsFastScrollEnabled) {
if (mScroller == null)
mScroller = new IndexScroller(getContext(), this);
} else {
if (mScroller != null) {
mScroller.hide();
mScroller = null;
}
}
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
// Overlay index bar
if (mScroller != null)
mScroller.draw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
// Intercept ListView’s touch event
if (mScroller != null && mScroller.onTouchEvent(ev))
return true;
if (mGestureDetector == null) {
// 创建一个GestureDetector(手势探测器)
mGestureDetector = new GestureDetector(getContext(),
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
// If fling happens, index bar shows
// 显示索引条
mScroller.show();
return super.onFling(e1, e2, velocityX, velocityY);
}
});
}
mGestureDetector.onTouchEvent(ev);
return super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
@Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
if (mScroller != null)
mScroller.setAdapter(adapter);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mScroller != null)
mScroller.onSizeChanged(w, h, oldw, oldh);
}
}
索引条
/*
-
Copyright 2011 woozzu
-
Licensed under the Apache License, Version 2.0 (the “License”);
-
you may not use this file except in compliance with the License.
-
You may obtain a copy of the License at
-
http://www.apache.org/licenses/LICENSE-2.0
-
Unless required by applicable law or agreed to in writing, software
-
distributed under the License is distributed on an “AS IS” BASIS,
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-
See the License for the specific language governing permissions and
-
limitations under the License.
*/
package com.wwj.indexableListView.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.widget.Adapter;
import android.widget.ListView;
import android.widget.SectionIndexer;
/**
-
右侧的索引条
-
@author by 佚名
*/
public class IndexScroller {
private float mIndexbarWidth; // 索引条宽度
private float mIndexbarMargin; // 索引条外边距
private float mPreviewPadding; //
private float mDensity; // 密度
private float mScaledDensity; // 缩放密度
private float mAlphaRate; // 透明度
private int mState = STATE_HIDDEN; // 状态
private int mListViewWidth; // ListView宽度
private int mListViewHeight; // ListView高度
private int mCurrentSection = -1; // 当前部分
private boolean mIsIndexing = false; // 是否正在索引
private ListView mListView = null;
private SectionIndexer mIndexer = null;
private String[] mSections = null;
private RectF mIndexbarRect;
// 4种状态(已隐藏、正在显示、已显示、正在隐藏)
private static final int STATE_HIDDEN = 0;
private static final int STATE_SHOWING = 1;
private static final int STATE_SHOWN = 2;
private static final int STATE_HIDING = 3;
public IndexScroller(Context context, ListView lv) {
mDensity = context.getResources().getDisplayMetrics().density;
mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
mListView = lv;
setAdapter(mListView.getAdapter());
mIndexbarWidth = 20 * mDensity; // 索引条宽度
mIndexbarMargin = 10 * mDensity;// 索引条间距
mPreviewPadding = 5 * mDensity; // 内边距
}
public void draw(Canvas canvas) {
if (mState == STATE_HIDDEN)
return;
// mAlphaRate determines the rate of opacity
Paint indexbarPaint = new Paint();
indexbarPaint.setColor(Color.BLACK);
indexbarPaint.setAlpha((int) (64 * mAlphaRate));
indexbarPaint.setAntiAlias(true);
// 画右侧字母索引的圆矩形
canvas.drawRoundRect(mIndexbarRect, 5 * mDensity, 5 * mDensity,
indexbarPaint);
if (mSections != null && mSections.length > 0) {
// Preview is shown when mCurrentSection is set
if (mCurrentSection >= 0) {
Paint previewPaint = new Paint(); // 用来绘画所以条背景的画笔
previewPaint.setColor(Color.BLACK);// 设置画笔颜色为黑色
previewPaint.setAlpha(96); // 设置透明度
previewPaint.setAntiAlias(true);// 设置抗锯齿
previewPaint.setShadowLayer(3, 0, 0, Color.argb(64, 0, 0, 0)); // 设置阴影层
Paint previewTextPaint = new Paint(); // 用来绘画索引字母的画笔
previewTextPaint.setColor(Color.WHITE); // 设置画笔为白色
previewTextPaint.setAntiAlias(true); // 设置抗锯齿
previewTextPaint.setTextSize(50 * mScaledDensity); // 设置字体大小
// 文本的宽度
float previewTextWidth = previewTextPaint
.measureText(mSections[mCurrentSection]);
float previewSize = 2 * mPreviewPadding
- previewTextPaint.descent()
- previewTextPaint.ascent();
RectF previewRect = new RectF(
(mListViewWidth - previewSize) / 2,
(mListViewHeight - previewSize) / 2,
(mListViewWidth - previewSize) / 2 + previewSize,
(mListViewHeight - previewSize) / 2 + previewSize);
// 中间索引的那个框
canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity,
previewPaint);
// 绘画索引字母
canvas.drawText(
mSections[mCurrentSection],
previewRect.left + (previewSize - previewTextWidth) / 2
- 1,
previewRect.top + mPreviewPadding
- previewTextPaint.ascent() + 1,
previewTextPaint);
}
// 绘画右侧索引条的字母
Paint indexPaint = new Paint();
indexPaint.setColor(Color.WHITE);
indexPaint.setAlpha((int) (255 * mAlphaRate));
indexPaint.setAntiAlias(true);
indexPaint.setTextSize(12 * mScaledDensity);
float sectionHeight = (mIndexbarRect.height() - 2 * mIndexbarMargin)
/ mSections.length;
float paddingTop = (sectionHeight - (indexPaint.descent() - indexPaint
.ascent())) / 2;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/a738197d981e896209795f4f5eaffc03.jpeg)
小结
有了这么多优秀的开发工具,可以做出更高质量的Android应用。
当然了,“打铁还需自身硬”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。
在这里我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。
总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-U1EYQllg-1712513701886)]
[外链图片转存中…(img-xgHcxRhH-1712513701886)]
[外链图片转存中…(img-gv3Q2zE6-1712513701887)]
[外链图片转存中…(img-g4gyTsuO-1712513701887)]
[外链图片转存中…(img-trwtralP-1712513701887)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/a738197d981e896209795f4f5eaffc03.jpeg)
小结
有了这么多优秀的开发工具,可以做出更高质量的Android应用。
当然了,“打铁还需自身硬”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。
在这里我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。
总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!