最近有点忙,项目进度跟的比较紧。最近需求那边让我们写一个左右和上下都可滑动的列表,用来展示多个Title的值。这里我把需求简化了一下。老规矩,先看图。

320c499da51d

在看到需求的时候,有在网上看看有没有别人造好的轮子,找是找到了,但是它是用HorizontalScrollView、ScrollView、ListView实现的,效果是有了,但是ListView没有复用了,导致我一次性加载800条数据时,界面卡顿,体验很不好。而且它的点击效果只能分别点击左边和右边,并不能点击的时候整个item都高亮。

所以,这里我就去研究了一下该怎么实现这个需求。

这里我封装了一个HRecycleView去继承RelativeLayout。

分为上下两部分

① TitleLayout

包括左边的"名称"(固定不可滑动),右边的"Title"(多个可滑动)

② Title的数据

使用的是RecyclerView

这里只要处理水平方向的手势滑动即可,所以,我们需要去拦截手势,使用scrollTo方法实现水平滚动。请看代码的详细注释。

/**

* Created by chawei on 2018/4/29.

*/

public class HRecyclerView extends RelativeLayout {

//头部title布局

private LinearLayout mRightTitleLayout;

//手指按下时的位置

private float mStartX = 0;

//滑动时和按下时的差值

private int mMoveOffsetX = 0;

//最大可滑动差值

private int mFixX = 0;

//左边标题集合

private String[] mLeftTextList;

//左边标题的宽度集合

private int[] mLeftTextWidthList;

//右边标题集合

private String[] mRightTitleList = new String[]{};

//右边标题的宽度集合

private int[] mRightTitleWidthList = null;

//展示数据时使用的RecycleView

private RecyclerView mRecyclerView;

//RecycleView的Adapter

private Object mAdapter;

//需要滑动的View集合

private ArrayList mMoveViewList = new ArrayList();

private Context context;

//右边可滑动的总宽度

private int mRightTotalWidth = 0;

//右边单个view的宽度

private int mRightItemWidth = 60;

//左边view的宽度

private int mLeftViewWidth = 80;

//左边view的高度

private int mLeftViewHeight=40;

//触发拦截手势的最小值

private int mTriggerMoveDis=30;

public HRecyclerView(Context context) {

this(context, null);

}

public HRecyclerView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public HRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

this.context = context;

}

private void initView() {

LinearLayout linearLayout = new LinearLayout(getContext());

linearLayout.setOrientation(LinearLayout.VERTICAL);

linearLayout.addView(createHeadLayout());

linearLayout.addView(createMoveRecyclerView());

addView(linearLayout, new LayoutParams(LayoutParams.MATCH_PARENT,

ViewGroup.LayoutParams.MATCH_PARENT));

}

/**

* 创建头部布局

* @return

*/

private View createHeadLayout() {

LinearLayout headLayout = new LinearLayout(getContext());

headLayout.setGravity(Gravity.CENTER);

LinearLayout leftLayout = new LinearLayout(getContext());

addListHeaderTextView(mLeftTextList[0], mLeftTextWidthList[0], leftLayout);

leftLayout.setGravity(Gravity.CENTER);

headLayout.addView(leftLayout, 0, new ViewGroup.LayoutParams(dip2px(context, mLeftViewWidth), dip2px(context, mLeftViewHeight)));

mRightTitleLayout = new LinearLayout(getContext());

for (int i = 0; i < mRightTitleList.length; i++) {

addListHeaderTextView(mRightTitleList[i], mRightTitleWidthList[i], mRightTitleLayout);

}

headLayout.addView(mRightTitleLayout);

return headLayout;

}

/**

* 创建数据展示布局

* @return

*/

private View createMoveRecyclerView() {

RelativeLayout linearLayout = new RelativeLayout(getContext());

mRecyclerView = new RecyclerView(getContext());

LinearLayoutManager layoutManager = new LinearLayoutManager(context);

layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

mRecyclerView.setLayoutManager(layoutManager);

if(null !=mAdapter){

if (mAdapter instanceof CommonAdapter) {

mRecyclerView.setAdapter((CommonAdapter) mAdapter);

mMoveViewList = ((CommonAdapter) mAdapter).getMoveViewList();

}

}

linearLayout.addView(mRecyclerView, new LayoutParams(LayoutParams.MATCH_PARENT,

LayoutParams.MATCH_PARENT));

return linearLayout;

}

/**

* 设置adapter

* @param adapter

*/

public void setAdapter(Object adapter) {

mAdapter = adapter;

initView();

}

/**

* 设置头部title单个布局

* @param headerName

* @param width

* @param leftLayout

* @return

*/

private TextView addListHeaderTextView(String headerName, int width, LinearLayout leftLayout) {

TextView textView = new TextView(getContext());

textView.setText(headerName);

textView.setGravity(Gravity.CENTER);

leftLayout.addView(textView, width, dip2px(context, 50));

return textView;

}

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

mStartX = ev.getX();

break;

case MotionEvent.ACTION_MOVE:

int offsetX = (int) Math.abs(ev.getX() - mStartX);

if (offsetX > mTriggerMoveDis) {//水平移动大于30触发拦截

return true;

} else {

return false;

}

}

return super.onInterceptTouchEvent(ev);

}

/**

* 右边可滑动的总宽度

* @return

*/

private int rightTitleTotalWidth() {

if (0 == mRightTotalWidth) {

for (int i = 0; i < mRightTitleWidthList.length; i++) {

mRightTotalWidth = mRightTotalWidth + mRightTitleWidthList[i];

}

}

return mRightTotalWidth;

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

return true;

case MotionEvent.ACTION_MOVE:

int offsetX = (int) Math.abs(event.getX() - mStartX);

if (offsetX > 30) {

mMoveOffsetX = (int) (mStartX - event.getX() + mFixX);

if (0 > mMoveOffsetX) {

mMoveOffsetX = 0;

} else {

//当滑动大于最大宽度时,不在滑动(右边到头了)

if ((mRightTitleLayout.getWidth() + mMoveOffsetX) > rightTitleTotalWidth()) {

mMoveOffsetX = rightTitleTotalWidth() - mRightTitleLayout.getWidth();

}

}

//跟随手指向右滚动

mRightTitleLayout.scrollTo(mMoveOffsetX, 0);

if (null != mMoveViewList) {

for (int i = 0; i < mMoveViewList.size(); i++) {

//使每个item随着手指向右滚动

mMoveViewList.get(i).scrollTo(mMoveOffsetX, 0);

}

}

}

break;

case MotionEvent.ACTION_UP:

mFixX = mMoveOffsetX; //设置最大水平平移的宽度

break;

}

return super.onTouchEvent(event);

}

/**

* 列表头部数据

* @param headerListData

*/

public void setHeaderListData(String[] headerListData) {

mRightTitleList = headerListData;

mRightTitleWidthList = new int[headerListData.length];

for (int i = 0; i < headerListData.length; i++) {

mRightTitleWidthList[i] = dip2px(context, mRightItemWidth);

}

mLeftTextWidthList = new int[]{dip2px(context, mLeftViewWidth)};

mLeftTextList = new String[]{"名称"};

}

}

这里模拟了一次加载1W条数据,没有卡顿效果。

/**

* Created by chawei on 2018/4/29.

*/

public class CoinActivity extends AppCompatActivity {

private ArrayList mDataModels;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_stock_layout);

HRecyclerView hRecyclerView= (HRecyclerView) findViewById(R.id.id_hrecyclerview);

mDataModels = new ArrayList<>();

for(int i=0;i<10000;i++) {

CoinInfo coinInfo = new CoinInfo();

coinInfo.name = "USDT";

coinInfo.priceLast="20.0";

coinInfo.riseRate24="0.2";

coinInfo.vol24="10020";

coinInfo.close="22.2";

coinInfo.open="40.0";

coinInfo.bid="33.2";

coinInfo.ask="19.0";

coinInfo.amountPercent = "33.3%";

mDataModels.add(coinInfo);

}

hRecyclerView.setHeaderListData(getResources().getStringArray(R.array.right_title_name));

CoinAdapter adapter = new CoinAdapter(this, mDataModels, R.layout.item_layout, new CommonViewHolder.onItemCommonClickListener() {

@Override

public void onItemClickListener(int position) {

Toast.makeText(CoinActivity.this, "position--->"+position, Toast.LENGTH_SHORT).show();

}

@Override

public void onItemLongClickListener(int position) {

}

});

hRecyclerView.setAdapter(adapter);

}

}

这里封装了RecyclerView的通用Adapter和ViewHolder。所以如果要使用HRecyclerView的setAdapter就必须继承封装的通用Adapter。

CommonAdapter和CommonViewHolder请点击demo地址查看

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐