列表粘性分组之按首字母分组国家选区号
Android原生版本
直接先看UI图,效果如下
本来看起来也不难,我就想着上面常用区号那块不动,下面的列表滑动就行,但IOS说他滑动的时候上面也滑上去了,好吧,这也行;但最终效果做出来后,IOS滑动后会有按照国家名称首字母进行粘性分组,好吧,为了提升自己,我也决定做得跟IOS一样,不说废话了,直接上代码
引入流布局控件
//流布局
api 'com.google.android:flexbox:1.0.0'
布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/rl_content"android:layout_width="match_parent"android:layout_height="@dimen/dp_area_code_pop_height"app:defaultColor="@color/white"app:topLeftRadius="@dimen/dp_10"app:topRightRadius="@dimen/dp_10"tools:background="@color/white"><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_gravity="center"android:paddingVertical="@dimen/dp_20"android:text="@string/sel_international_code"android:textColor="@color/col_3a3b3d"android:textSize="@dimen/sp_18" /><com.yunqu.quyun_res.widget.StatusLayoutandroid:id="@+id/status"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/tv_title"app:status="LOADING"app:toolsStatus="NORMAL"><ProgressBarstyle="?android:attr/progressBarStyleSmall"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"app:layout_status="LOADING" /><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"app:layout_status="NORMAL"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_general"android:background="@color/white"android:layout_width="match_parent"android:layout_height="wrap_content"android:paddingHorizontal="@dimen/dp_20"android:paddingVertical="@dimen/dp_10"tools:itemCount="4"tools:listitem="@layout/item_general_code" /></FrameLayout></com.yunqu.quyun_res.widget.StatusLayout><Viewandroid:id="@+id/v_divider"android:layout_width="match_parent"android:layout_height="@dimen/dp_0_5"android:layout_above="@id/tv_cancel"android:background="@color/col_e0e7ee" /><Buttonandroid:id="@+id/tv_cancel"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:background="@color/white"android:gravity="center"android:paddingVertical="@dimen/dp_17"android:text="@string/cancel"android:textColor="@color/col_3a3b3d"android:textSize="@dimen/sp_16"app:textPressedColor="@color/col_acb2b8" /><com.yunqu.quyun_res.widget.TenXuLetterBarandroid:id="@+id/txlb"android:layout_width="@dimen/dp_15"android:layout_height="wrap_content"android:layout_below="@id/tv_title"android:layout_alignBottom="@id/v_divider"android:layout_alignParentEnd="true"android:layout_marginTop="@dimen/dp_70"android:layout_marginEnd="@dimen/dp_20"android:layout_marginBottom="@dimen/dp_10"android:minHeight="@dimen/dp_area_code_mh"app:txlb_item_background_def="@drawable/bg_letter_def"app:txlb_item_background_sel="@drawable/bg_letter_sel"app:txlb_item_text_color_def="@color/col_9b9b9b"app:txlb_item_text_color_sel="@color/white" /><TextViewandroid:id="@+id/tv_letter"android:layout_width="@dimen/dp_55"android:layout_height="@dimen/dp_55"android:layout_centerInParent="true"android:layout_gravity="center"android:background="@drawable/bg_circle_80000000"android:gravity="center"android:textColor="@color/white"android:textSize="18sp"android:visibility="gone"tools:visibility="visible" /></RelativeLayout>
item_common_code.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"android:paddingBottom="@dimen/dp_10"tools:ignore="MissingDefaultResource"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_commons"android:layout_width="match_parent"android:layout_height="wrap_content"android:nestedScrollingEnabled="false"tools:itemCount="2"tools:listitem="@layout/item_common_code" /></FrameLayout>
item_common_code_tip.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"tools:ignore="MissingDefaultResource"><TextViewandroid:id="@+id/tv_common_tip"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/common_code"android:textColor="@color/col_9b9b9b"android:textSize="@dimen/sp_14" /></FrameLayout>
item_general_code.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/tv_code"android:layout_width="match_parent"android:layout_height="wrap_content"android:paddingVertical="@dimen/dp_12"android:includeFontPadding="false"android:textColor="@color/col_111212"android:textSize="@dimen/sp_14"tools:text="中国大陆+86" /></LinearLayout>
item_general_code_group.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"tools:ignore="MissingDefaultResource"><LinearLayoutandroid:id="@+id/ll_letter"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"tools:ignore="UselessParent"><TextViewandroid:id="@+id/tv_letter"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="@color/col_111212"android:textSize="@dimen/sp_14"android:textStyle="bold"tools:text="A" /><Viewandroid:layout_width="match_parent"android:layout_height="@dimen/dp_0_5"android:layout_marginTop="@dimen/dp_10"android:background="@color/col_e0e7ee" /></LinearLayout></LinearLayout>
其中com.yunqu.quyun_res.widget.StatusLayout控件是自定义的一个FrameLayout状态控件,这里就不放出来了,其实主要就是控制加载数据过程中的切换,根据逻辑用GONE和VISIBLE也是一样的
com.yunqu.quyun_res.widget.TenXuLetterBar控件代码如下
public class TenXuLetterBar extends View {private static final String TAG = "TenXuLetterBar";// private final List<String> mLetters = new ArrayList<>();private final String[] mLettersHadWell = 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 final String[] mLetters = 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 final Paint mPaint;private Drawable mItemBackgroundDef;private Drawable mItemBackgroundSel;private final int mItemTextColorDef;private final int mItemTextColorSel;private final boolean mNeedWell;// private int mLetterWidth;private int mLetterIndex = -1;private OnLetterChangeListner onLetterChangeListener;//选中字母后的回调public TenXuLetterBar(Context context) {this(context, null);}public TenXuLetterBar(Context context, AttributeSet attrs) {this(context, attrs, 0);}public TenXuLetterBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray typedArray =context.obtainStyledAttributes(attrs, R.styleable.TenXuLetterBar);mItemBackgroundDef = typedArray.getDrawable(