忘了贴图 copy代码运行看效果
一、TabLayout+ViewPager+Fragment
1.1、MainActivity.java中使用
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private ViewPager mViewPager;
private LinearLayout mLinearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
mViewPager = (ViewPager) findViewById(R.id.viewPager);
/**
* 将TabLayout与ViewPager结合
*
*/
//步骤一:给VIewPager设置Adapter(FragmentPagerAdapter)
MyViewPagerAdapter adapter = new MyViewPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(adapter);
/**
* 步骤二(到了步骤二可以看效果了,后面步骤是设置indicator属性等代码)
*
* 很牛逼的一个方法
*
* 关联TabLayout与ViewPager,互相绑定,且适配器必须重写getPageTitle()方法
*
* 这个方法三个作用
* 1、从ViewPager中获取TabLayout的Title----getPageTitle()
* 2、ViewPager滑动时,设置TabLayout的Title和indicator
* 3、点击TabLayout时,ViewPager相应变化
*/
mTabLayout.setupWithViewPager(mViewPager);
//步骤三 设置分割线:参考https://www.jianshu.com/p/bbefb97cccdd
mLinearLayout = (LinearLayout) mTabLayout.getChildAt(0);
// 在所有子控件的中间显示分割线(还可 只显示顶部、尾部和不显示分割线)
mLinearLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
// 设置分割线的距离本身(LinearLayout)的内间距
mLinearLayout.setDividerPadding(50);
// 设置分割线的样式
mLinearLayout.setDividerDrawable(ContextCompat.getDrawable(this, R.drawable.divider_vertical));
mLinearLayout.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
//步骤四 设置指示器的长度(本来是不可设置的),这里是通过Tab外间距的方式
// 自定义指示器(Indicator)的“长度”的两种方法,会有跳动的bug情况未解决,不推荐使用只做为一种示例
// 方法一:反射
// setIndicator(mTabLayout,10,10);
// 方法二:查找子控件
int left = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, Resources.getSystem().getDisplayMetrics());
int right = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, Resources.getSystem().getDisplayMetrics());
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View tabView = mLinearLayout.getChildAt(i);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
params.leftMargin = left;
params.rightMargin = right;
tabView.setLayoutParams(params);
}
}
public void setIndicator(TabLayout tabs, int leftDip, int rightDip) {
Class> tabLayout = tabs.getClass();
Field tabStrip = null;//java.lang.reflect.Field
try {
tabStrip = tabLayout.getDeclaredField("mTabStrip");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
tabStrip.setAccessible(true);
LinearLayout llTab = null;
try {
llTab = (LinearLayout) tabStrip.get(tabs);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
int left = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, leftDip, Resources.getSystem().getDisplayMetrics());
int right = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rightDip, Resources.getSystem().getDisplayMetrics());
for (int i = 0; i < llTab.getChildCount(); i++) {
View child = llTab.getChildAt(i);
child.setPadding(0, 0, 0, 0);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
params.leftMargin = left;
params.rightMargin = right;
child.setLayoutParams(params);
child.invalidate();
}
}
//步骤一(1)
private class MyViewPagerAdapter extends FragmentPagerAdapter {
//步骤一(1)、② 数据
private final String[] title = new String[]{
"推荐", "热点", "视频", "图片", "新闻",
"汽车", "科技","财经", "游戏", "广州","旅游"};
public MyViewPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
//步骤一(1)、③ 实例化fragment
Fragment fragment = new TextFragment();
//给fragment传数据
Bundle bundle = new Bundle();
bundle.putString("title", title[position]);
fragment.setArguments(bundle);
return fragment;
}
@Override
public int getCount() {
return title.length;
}
//步骤一(1)、① 实例化fragment
@Override
public CharSequence getPageTitle(int position) {
return title[position];
}
}
}
1.2、在activity_main.xml中
二、ListPopupWindow
2.1、在MainActivity.java中
public class MainActivity extends AppCompatActivity {
private ListPopupWindow mListPopupWindow;
private ArrayAdapter mAdapter;
private String[] mItemArr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mItemArr = new String[]{"test 1", "test 2", "test 3", "test 4", "test 5", "test 6", "test 7", "test 8"};
mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mItemArr);
}
public void showPopupWindow(View view){
if (mListPopupWindow == null)
mListPopupWindow = new ListPopupWindow(this);
//应该是 设置 ListPopupWindow 的数据适配器
mListPopupWindow.setAdapter(mAdapter);
//应该是 设置 ListPopupWindow 的显示位置(在指定控件下方)
mListPopupWindow.setAnchorView(view);
//应该是 设置上下边距的距离
mListPopupWindow.setVerticalOffset(10);
//应该是 设置 ListPopupWindow 的宽度
mListPopupWindow.setWidth(300);
//应该是 设置 ListPopupWindow 的高度
mListPopupWindow.setHeight(600);
//应该是 设置 ListPopupWindow 的条目点击事件(必须在show方法前设置,否则无效)
mListPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
Toast.makeText(getApplicationContext(), mItemArr[position], Toast.LENGTH_SHORT).show();
mListPopupWindow.dismiss();
}
});
mListPopupWindow.show();
}
2.2、在 activity_main.xml 中
三、PopupMenu的简单使用
3.1、在MainActivity.java中
public void showPopupMenu(View view) throws NoSuchFieldException, IllegalAccessException {
PopupMenu popupMenu = new PopupMenu(this, view);
//设置 PopupMenu 的显示菜单项
popupMenu.inflate(R.menu.main);
// popupMenu.getMenuInflater().inflate(R.menu.main, popupMenu.getMenu());//上一行与这一行效果一样
//默认 PopupMenu 不显示条目icon,可以通过反射来强制使其显示icon
Field field = popupMenu.getClass().getDeclaredField("mPopup");
field.setAccessible(true);
MenuPopupHelper mHelper = (MenuPopupHelper) field.get(popupMenu);
mHelper.setForceShowIcon(true);
//设置 PopupMenu 的条目点击事件(点击后会自动dismiss)
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(getApplicationContext(), item.getTitle(), Toast.LENGTH_SHORT).show();
return false;
}
});
//显示 PopupMenu
popupMenu.show();
}
3.2、在 activity_main.xml 中
3.3、main.xml 资源(res/menu/main.xml)
四、LinearLayoutCompat的简单使用
4.1、在MainActivity.java中
public class MainActivity extends AppCompatActivity {
private LinearLayoutCompat linearLayoutCompat;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linearLayoutCompat = (LinearLayoutCompat) findViewById(R.id.linearLayoutCompat);
}
//布局的前面一个分割线
public void beginning(View view) {
linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_BEGINNING);
}
//布局的除了前面和后面没有分割线,中间控件之间都有分割线
public void middle(View view) {
linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_MIDDLE);
}
//布局的尾部一个分割线
public void end(View view) {
linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_END);
}
//布局的除了尾部没有分割线,其他有(前面和中间)
public void beginning_middle(View view) {
linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_BEGINNING | LinearLayoutCompat.SHOW_DIVIDER_MIDDLE);
}
//布局的除了前面没有分割线,其他有(中间和后面)
public void end_middle(View view) {
linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_MIDDLE | LinearLayoutCompat.SHOW_DIVIDER_END);
}
}
4.2、在 activity_main.xml 中
五、RecyclerView.ItemDecoration 条目item装饰 的简单使用
①、水平/垂直分割线
②、网格布局分割线
③、侧边字母提示样式
④、悬浮头布局样式
5.1、水平/垂直 分割线 装饰
5.1.1、在MainActivity.java中
public class MainActivity extends AppCompatActivity {
private List mData = new ArrayList<>();
private RecyclerView mRv;
private MyAdapter mMyAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRv = (RecyclerView) findViewById(R.id.rv);
initDecoration();
initData();
initRecyclerView();
}
//初始化修饰布局(分割线)
private void initDecoration() {
MyDecorationOne decorationOne = new MyDecorationOne(this, LinearLayoutManager.VERTICAL);
mRv.addItemDecoration(decorationOne);
}
//初始化数据
private void initData() {
for (int i = 0; i < 100; i++) {
mData.add("item " + i);
}
}
//初始化recyclerview,关联adapter
private void initRecyclerView() {
mMyAdapter = new MyAdapter(mData);
mRv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
mRv.setAdapter(mMyAdapter);
}
}
5.1.2、在activity_main.xml中
5.1.3、自定义装饰 MyDecorationOne.java
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Created by ${chenyuexueer} on 2018/5/9.
*
* 说明:自定义recyclerview的自定义条目装饰(分割线,当然它不仅仅可以作为分割线)
*
* 1、继承RecyclerView.ItemDecoration,
* 重写 public void onDraw()和 public void getItemOffsets()方法(并不是必须,可不要)
*
* 2、构造方法,初始化属性等
*
* 3、设计绘图方法
*/
public class MyDecorationOne extends RecyclerView.ItemDecoration {
int orientation = RecyclerView.VERTICAL;//默认垂直
private final Drawable mDivider;
public MyDecorationOne(Context context, int orientation) {
this.orientation = orientation;//初始化recyclerview布局方向,activity传过来的recyclerview的布局方向
int[] attrs = new int[]{android.R.attr.listDivider};//系统提供的属性
TypedArray a = context.obtainStyledAttributes(attrs);//属性组
mDivider = a.getDrawable(0);//取组中第一个
a.recycle();//回收
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
int childCount = parent.getChildCount();//recyclerview的子item的条数
if (orientation == RecyclerView.HORIZONTAL) {//activity那边设置是水平布局,则绘制一个个垂直()装饰
drawVertical(c, parent,childCount);
} else if (orientation == RecyclerView.VERTICAL) {//activity那边设置是水平布局,则绘制一个个垂直装饰
drawHorizontal(c, parent,childCount);
}
}
//绘制垂直装饰
private void drawVertical(Canvas c, RecyclerView parent, int childCount) {
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);//第i条item的view对象
//第i条item的view对象的布局参数
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
//计算装饰(分割线)的绘制参数(边距)
int left = child.getRight() + params.rightMargin;
int top = child.getTop() - params.topMargin;
int right = left + mDivider.getIntrinsicWidth();
int bottom = child.getBottom() + params.bottomMargin;
//设置装饰(分割线)边距
mDivider.setBounds(left, top, right, bottom);
//开始绘制
mDivider.draw(c);
}
}
//绘制水平装饰
private void drawHorizontal(Canvas c, RecyclerView parent, int childCount) {
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getLeft() - params.leftMargin;
int top = child.getBottom() + params.bottomMargin;
int right = child.getRight() + params.rightMargin;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
/**
* 设置条目周边的偏移量(即偏移分割线的大小距离)
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (orientation == RecyclerView.HORIZONTAL) {
//画垂直线
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
} else if (orientation == RecyclerView.VERTICAL) {
//画水平线
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
}
}
5.1.4、MyAdapter.java
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter {
private List mData;
public MyAdapter(List data) {
mData = data;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = View.inflate(parent.getContext(), android.R.layout.simple_list_item_1, null);
itemView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.mTv.setText(mData.get(position));
}
@Override
public int getItemCount() {
return mData.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView mTv;
public MyViewHolder(View itemView) {
super(itemView);
mTv = (TextView) itemView.findViewById(android.R.id.text1);
}
}
}
5.2、网格分割 装饰
5.2.1、MainActivity.java
public class MainActivity extends AppCompatActivity {
private List mData = new ArrayList<>();
private RecyclerView mRv;
private MyAdapter mMyAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRv = (RecyclerView) findViewById(R.id.rv);
initDecoration();
initData();
initRecyclerView();
}
//初始化修饰布局(分割线)
private void initDecoration() {
MyDecorationTwo decorationTwo = new MyDecorationTwo(this);
mRv.addItemDecoration(decorationTwo);
}
//初始化数据
private void initData() {
for (int i = 0; i < 100; i++) {
mData.add("item " + i);
}
}
//初始化recyclerview,关联adapter,这里使用GridLayoutManager表格布局
private void initRecyclerView() {
mMyAdapter = new MyAdapter(mData);
mRv.setLayoutManager(new GridLayoutManager(this, 4));
mRv.setAdapter(mMyAdapter);
}
}
5.2.2、activity_main.xml
具体代码----同上(5.1.2、activity_main.xml)
5.2.3、 MyAdapter.java
具体代码----同上(5.1.4、MyAdapter.java)
5.2.4、自定义装饰 MyDecorationTwo.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Created by ${chenyuexueer} on 2018/5/9.
*
* 说明:自定义recyclerview的自定义条目装饰(网格分割)
*
* 1、构造方法,初始化属性等
*
* 2、继承RecyclerView.ItemDecoration,
* 重写 public void onDraw()和 public void getItemOffsets()方法
* public void getItemOffsets()方法并不是必须,可不用(没有节点),可以注释掉这个方法看效果
*
* 3、设计绘图方法
*/
public class MyDecorationTwo extends RecyclerView.ItemDecoration {
private final Drawable mDivider;
public MyDecorationTwo(Context context) {//构造方法初始化数据
//与MyDecorationOne相比,这里是自定义的资源文件,MyDecorationOne是系统提供的资源文件
mDivider = context.getResources().getDrawable(R.drawable.divider);
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
int childCount = parent.getChildCount();//recyclerview的子item的条数
//水平垂直都要绘制分割线,这样才能形成网格
drawVertical(c, parent,childCount);
drawHorizontal(c, parent,childCount);
}
//绘制垂直装饰
private void drawVertical(Canvas c, RecyclerView parent, int childCount) {
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);//第i条item的view对象
//第i条item的view对象的布局参数
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
//计算装饰(分割线)的绘制参数(边距)
int left = child.getRight() + params.rightMargin;
int top = child.getTop() - params.topMargin;
int right = left + mDivider.getIntrinsicWidth();
int bottom = child.getBottom() + params.bottomMargin;
//设置装饰(分割线)边距
mDivider.setBounds(left, top, right, bottom);
//开始绘制
mDivider.draw(c);
}
}
//绘制水平装饰
private void drawHorizontal(Canvas c, RecyclerView parent, int childCount) {
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getLeft() - params.leftMargin;
int top = child.getBottom() + params.bottomMargin;
int right = child.getRight() + params.rightMargin;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
/**
* 设置条目右下边的偏移量(效果:右下边有一个空白的小正方形节点)
*/
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
super.getItemOffsets(outRect, itemPosition, parent);
//getIntrinsicWidth()/getIntrinsicHeight()与getWidth()/getHeight()区别具体请自行百度谷歌
int right = mDivider.getIntrinsicWidth();
int bottom = mDivider.getIntrinsicHeight();
//第itemPosition个条目item的最后一列,即正方形的下边,则不需要绘制右边
if (isLastSpan(itemPosition, parent)) {
right = 0;
}
//第itemPosition个条目item的最后一行,即正方形的右边,则不需要绘制底部
if (isLastRow(itemPosition, parent)) {
bottom = 0;
}
outRect.set(0, 0, right, bottom);
}
public boolean isLastRow(int itemPosition, RecyclerView parent) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
int itemCount = parent.getAdapter().getItemCount();
if ((itemCount - itemPosition - 1) < spanCount)//则不需要底部
return true;
}
return false;
}
public boolean isLastSpan(int itemPosition, RecyclerView parent) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
if ((itemPosition + 1) % spanCount == 0)//则不需要绘制右边
return true;
}
return false;
}
}
5.2.4、divider.xml 资源文件 res/drawable/divider.xml
5.3、侧边字母提示 装饰
需要依赖 拼音工具包
sourceforge 开源项目jar包
Github 依赖
5.3.1、MainActivity.java
public class MainActivity extends AppCompatActivity {
private List mData = new ArrayList<>();
private RecyclerView mRv;
private MyAdapter mMyAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRv = (RecyclerView) findViewById(R.id.rv);
initData();
initDecoration();
initRecyclerView();
}
//初始化修饰布局(首字母提示)
private void initDecoration() {
MyDecorationThree decorationThree = new MyDecorationThree(this, mData);
mRv.addItemDecoration(decorationThree);
}
//初始化数据
private void initData() {
mData = Arrays.asList(Cheeses.NAMES);
//系统方法 排序
Collections.sort(mData, new Comparator() {
@Override
public int compare(String o1, String o2) {
return PinyinUtils.getPinyin(o1).compareTo(PinyinUtils.getPinyin(o2));
}
});
}
//初始化recyclerview,关联adapter
private void initRecyclerView() {
mMyAdapter = new MyAdapter(mData);
mRv.setLayoutManager(new LinearLayoutManager(this));
mRv.setAdapter(mMyAdapter);
}
}
5.3.2、拼音工具 PinyinUtils.java
/**
* Created by ${chenyuexueer}
*
* 说明:拼音工具(需要依赖或者导入pinyin4j-2.5.0.jar)
*/
public class PinyinUtils {
/**
* 根据传入的字符串(包含汉字),得到拼音
* 如:
*
* 好学 -> HAOXUE
* 好 学*& -> HAOXUE
* 好学y2 -> HAOXUE
*
* @param str 字符串
* @return
*/
public static String getPinyin(String str) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
StringBuilder sb = new StringBuilder();
char[] charArray = str.toCharArray();
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
// 如果是空格, 跳过
if (Character.isWhitespace(c)) {
continue;
}
if (c >= -127 && c < 128 || !(c >= 0x4E00 && c <= 0x9FA5)) {
// 满足条件 ,则肯定不是汉字
sb.append(c);
} else {
String s = "";
try {
// 通过char得到拼音集合. 单 -> dan, shan
s = PinyinHelper.toHanyuPinyinStringArray(c, format)[0];
sb.append(s);
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
sb.append(s);
}
}
}
return sb.toString();
}
}
5.3.3、自定义修饰类 MyDecorationThree .java
/**
* Created by ${chenyuexueer}
*
* 说明:
*/
public class MyDecorationThree extends RecyclerView.ItemDecoration {
Context mContext;
List mData;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//画笔
public MyDecorationThree(Context context, List data) {
mContext = context;
mData = data;
//画笔字体大小与颜色
paint.setTextSize(sp2px(16));
paint.setColor(Color.RED);
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
drawLetterToItemLeft(c, parent);
}
/**
* 绘制方法
* @param c 画布
* @param parent RecyclerView
*/
private void drawLetterToItemLeft(Canvas c, RecyclerView parent) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (!(layoutManager instanceof LinearLayoutManager)){
return;
}
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
int position = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition() + i;
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
float left = 0;
float top = child.getTop() - params.topMargin;
float right = child.getLeft() - params.leftMargin;
float bottom = child.getBottom() + params.bottomMargin;
float width = right - left;
float height = bottom - (bottom - top) / 2;
//当前名字拼音的第一个字母
String letter = PinyinUtils.getPinyin(mData.get(position)).charAt(0) + "";
if (position == 0) {
drawLetter(letter, width, height, c, parent);
} else {
String preLetter = PinyinUtils.getPinyin(mData.get(position - 1)).charAt(0) + "";
if (!letter.equalsIgnoreCase(preLetter)) {
drawLetter(letter, width, height, c, parent);
}
}
}
}
private void drawLetter(String letter, float width, float height, Canvas c, RecyclerView parent) {
float fontLength = getFontLength(paint, letter);
float fontHeight = getFontHeight(paint);
float tx = (width - fontLength) / 2;
float ty = height - fontHeight / 2 + getFontLeading(paint);
c.drawText(letter, tx, ty, paint);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(dip2px(40), 0, 0, 0);
}
private int dip2px(int dip) {
float density = mContext.getResources().getDisplayMetrics().density;
int px = (int) (dip * density + 0.5f);
return px;
}
public int sp2px(int sp) {
return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, mContext.getResources().getDisplayMetrics()) + 0.5f);
}
/**
* 返回指定笔和指定字符串的长度
*/
private float getFontLength(Paint paint, String str) {
return paint.measureText(str);
}
/**
* 返回指定笔的文字高度
*/
private float getFontHeight(Paint paint) {
Paint.FontMetrics fm = paint.getFontMetrics();
return fm.descent - fm.ascent;
}
/**
* 返回指定笔离文字顶部的基准距离
*/
private float getFontLeading(Paint paint) {
Paint.FontMetrics fm = paint.getFontMetrics();
return fm.leading - fm.ascent;
}
}
5.3.4、名字数组数据类Cheeses.java
/**
* Created by ${chenyuexueer}
* 说明:姓名数据
*/
public class Cheeses {
public static final String[] NAMES = new String[] { "宋江", "卢俊义", "吴用",
"公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进", "李应", "朱仝", "鲁智深",
"武松", "董平", "张清", "杨志", "徐宁", "索超", "戴宗", "刘唐", "李逵", "史进", "穆弘",
"雷横", "李俊", "阮小二", "张横", "阮小五", " 张顺", "阮小七", "杨雄", "石秀", "解珍",
" 解宝", "燕青", "朱武", "黄信", "孙立", "宣赞", "郝思文", "韩滔", "彭玘", "单廷珪",
"魏定国", "萧让", "裴宣", "欧鹏", "邓飞", " 燕顺", "杨林", "凌振", "蒋敬", "吕方",
"郭 盛", "安道全", "皇甫端", "王英", "扈三娘", "鲍旭", "樊瑞", "孔明", "孔亮", "项充",
"李衮", "金大坚", "马麟", "童威", "童猛", "孟康", "侯健", "陈达", "杨春", "郑天寿",
"陶宗旺", "宋清", "乐和", "龚旺", "丁得孙", "穆春", "曹正", "宋万", "杜迁", "薛永", "施恩",
"周通", "李忠", "杜兴", "汤隆", "邹渊", "邹润", "朱富", "朱贵", "蔡福", "蔡庆", "李立",
"李云", "焦挺", "石勇", "孙新", "顾大嫂", "张青", "孙二娘", " 王定六", "郁保四", "白胜",
"时迁", "段景柱" };
}
5.3.5、activity_main.xml
具体代码----同上(5.1.2、activity_main.xml)
5.3.6、 MyAdapter.java
具体代码----同上(5.1.4、MyAdapter.java)
5.4、悬浮头布局(使用ItemDecoration)
懒得写,将就着看这个吧,这个结合几个效果一起使用《Android二级联动》
MaterialDesign笔记(二)--控/组件简单使用
参考自