Android开源:水平方向listview,HorizontalListView

简介:

用法:

与普通listview一样。







项目地址:https://github.com/dinocore1/DevsmartLib-Android


代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
package  com.devsmart.android.ui;
import  java.util.LinkedList;
import  java.util.Queue;
import  android.content.Context;
import  android.database.DataSetObserver;
import  android.graphics.Rect;
import  android.util.AttributeSet;
import  android.view.GestureDetector;
import  android.view.GestureDetector.OnGestureListener;
import  android.view.MotionEvent;
import  android.view.View;
import  android.widget.AdapterView;
import  android.widget.ListAdapter;
import  android.widget.Scroller;
public  class  HorizontalListView  extends  AdapterView<ListAdapter> {
     public  boolean  mAlwaysOverrideTouch =  true ;
     protected  ListAdapter mAdapter;
     private  int  mLeftViewIndex = - 1 ;
     private  int  mRightViewIndex =  0 ;
     protected  int  mCurrentX;
     protected  int  mNextX;
     private  int  mMaxX = Integer.MAX_VALUE;
     private  int  mDisplayOffset =  0 ;
     protected  Scroller mScroller;
     private  GestureDetector mGesture;
     private  Queue<View> mRemovedViewQueue =  new  LinkedList<View>();
     private  OnItemSelectedListener mOnItemSelected;
     private  OnItemClickListener mOnItemClicked;
     private  OnItemLongClickListener mOnItemLongClicked;
     private  boolean  mDataChanged =  false ;
                  
     public  HorizontalListView(Context context, AttributeSet attrs) {
         super (context, attrs);
         initView();
     }
                  
     private  synchronized  void  initView() {
         mLeftViewIndex = - 1 ;
         mRightViewIndex =  0 ;
         mDisplayOffset =  0 ;
         mCurrentX =  0 ;
         mNextX =  0 ;
         mMaxX = Integer.MAX_VALUE;
         mScroller =  new  Scroller(getContext());
         mGesture =  new  GestureDetector(getContext(), mOnGesture);
     }
                  
     @Override
     public  void  setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {
         mOnItemSelected = listener;
     }
                  
     @Override
     public  void  setOnItemClickListener(AdapterView.OnItemClickListener listener){
         mOnItemClicked = listener;
     }
                  
     @Override
     public  void  setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) {
         mOnItemLongClicked = listener;
     }
     private  DataSetObserver mDataObserver =  new  DataSetObserver() {
         @Override
         public  void  onChanged() {
             synchronized (HorizontalListView. this ){
                 mDataChanged =  true ;
             }
             invalidate();
             requestLayout();
         }
         @Override
         public  void  onInvalidated() {
             reset();
             invalidate();
             requestLayout();
         }
                      
     };
     @Override
     public  ListAdapter getAdapter() {
         return  mAdapter;
     }
     @Override
     public  View getSelectedView() {
         //TODO: implement
         return  null ;
     }
     @Override
     public  void  setAdapter(ListAdapter adapter) {
         if (mAdapter !=  null ) {
             mAdapter.unregisterDataSetObserver(mDataObserver);
         }
         mAdapter = adapter;
         mAdapter.registerDataSetObserver(mDataObserver);
         reset();
     }
                  
     private  synchronized  void  reset(){
         initView();
         removeAllViewsInLayout();
         requestLayout();
     }
     @Override
     public  void  setSelection( int  position) {
         //TODO: implement
     }
                  
     private  void  addAndMeasureChild( final  View child,  int  viewPos) {
         LayoutParams params = child.getLayoutParams();
         if (params ==  null ) {
             params =  new  LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
         }
         addViewInLayout(child, viewPos, params,  true );
         child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
                 MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
     }
                  
                  
     @Override
     protected  synchronized  void  onLayout( boolean  changed,  int  left,  int  top,  int  right,  int  bottom) {
         super .onLayout(changed, left, top, right, bottom);
         if (mAdapter ==  null ){
             return ;
         }
                      
         if (mDataChanged){
             int  oldCurrentX = mCurrentX;
             initView();
             removeAllViewsInLayout();
             mNextX = oldCurrentX;
             mDataChanged =  false ;
         }
         if (mScroller.computeScrollOffset()){
             int  scrollx = mScroller.getCurrX();
             mNextX = scrollx;
         }
                      
         if (mNextX <=  0 ){
             mNextX =  0 ;
             mScroller.forceFinished( true );
         }
         if (mNextX >= mMaxX) {
             mNextX = mMaxX;
             mScroller.forceFinished( true );
         }
                      
         int  dx = mCurrentX - mNextX;
                      
         removeNonVisibleItems(dx);
         fillList(dx);
         positionItems(dx);
                      
         mCurrentX = mNextX;
                      
         if (!mScroller.isFinished()){
             post( new  Runnable(){
                 @Override
                 public  void  run() {
                     requestLayout();
                 }
             });
                          
         }
     }
                  
     private  void  fillList( final  int  dx) {
         int  edge =  0 ;
         View child = getChildAt(getChildCount()- 1 );
         if (child !=  null ) {
             edge = child.getRight();
         }
         fillListRight(edge, dx);
                      
         edge =  0 ;
         child = getChildAt( 0 );
         if (child !=  null ) {
             edge = child.getLeft();
         }
         fillListLeft(edge, dx);
                      
                      
     }
                  
     private  void  fillListRight( int  rightEdge,  final  int  dx) {
         while (rightEdge + dx < getWidth() && mRightViewIndex < mAdapter.getCount()) {
                          
             View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(),  this );
             addAndMeasureChild(child, - 1 );
             rightEdge += child.getMeasuredWidth();
                          
             if (mRightViewIndex == mAdapter.getCount()- 1 ) {
                 mMaxX = mCurrentX + rightEdge - getWidth();
             }
                          
             if  (mMaxX <  0 ) {
                 mMaxX =  0 ;
             }
             mRightViewIndex++;
         }
                      
     }
                  
     private  void  fillListLeft( int  leftEdge,  final  int  dx) {
         while (leftEdge + dx >  0  && mLeftViewIndex >=  0 ) {
             View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(),  this );
             addAndMeasureChild(child,  0 );
             leftEdge -= child.getMeasuredWidth();
             mLeftViewIndex--;
             mDisplayOffset -= child.getMeasuredWidth();
         }
     }
                  
     private  void  removeNonVisibleItems( final  int  dx) {
         View child = getChildAt( 0 );
         while (child !=  null  && child.getRight() + dx <=  0 ) {
             mDisplayOffset += child.getMeasuredWidth();
             mRemovedViewQueue.offer(child);
             removeViewInLayout(child);
             mLeftViewIndex++;
             child = getChildAt( 0 );
                          
         }
                      
         child = getChildAt(getChildCount()- 1 );
         while (child !=  null  && child.getLeft() + dx >= getWidth()) {
             mRemovedViewQueue.offer(child);
             removeViewInLayout(child);
             mRightViewIndex--;
             child = getChildAt(getChildCount()- 1 );
         }
     }
                  
     private  void  positionItems( final  int  dx) {
         if (getChildCount() >  0 ){
             mDisplayOffset += dx;
             int  left = mDisplayOffset;
             for ( int  i= 0 ;i<getChildCount();i++){
                 View child = getChildAt(i);
                 int  childWidth = child.getMeasuredWidth();
                 child.layout(left,  0 , left + childWidth, child.getMeasuredHeight());
                 left += childWidth + child.getPaddingRight();
             }
         }
     }
                  
     public  synchronized  void  scrollTo( int  x) {
         mScroller.startScroll(mNextX,  0 , x - mNextX,  0 );
         requestLayout();
     }
                  
     @Override
     public  boolean  dispatchTouchEvent(MotionEvent ev) {
         boolean  handled =  super .dispatchTouchEvent(ev);
         handled |= mGesture.onTouchEvent(ev);
         return  handled;
     }
                  
     protected  boolean  onFling(MotionEvent e1, MotionEvent e2,  float  velocityX,
                 float  velocityY) {
         synchronized (HorizontalListView. this ){
             mScroller.fling(mNextX,  0 , ( int )-velocityX,  0 0 , mMaxX,  0 0 );
         }
         requestLayout();
                      
         return  true ;
     }
                  
     protected  boolean  onDown(MotionEvent e) {
         mScroller.forceFinished( true );
         return  true ;
     }
                  
     private  OnGestureListener mOnGesture =  new  GestureDetector.SimpleOnGestureListener() {
         @Override
         public  boolean  onDown(MotionEvent e) {
             return  HorizontalListView. this .onDown(e);
         }
         @Override
         public  boolean  onFling(MotionEvent e1, MotionEvent e2,  float  velocityX,
                 float  velocityY) {
             return  HorizontalListView. this .onFling(e1, e2, velocityX, velocityY);
         }
         @Override
         public  boolean  onScroll(MotionEvent e1, MotionEvent e2,
                 float  distanceX,  float  distanceY) {
                          
             synchronized (HorizontalListView. this ){
                 mNextX += ( int )distanceX;
             }
             requestLayout();
                          
             return  true ;
         }
         @Override
         public  boolean  onSingleTapConfirmed(MotionEvent e) {
             for ( int  i= 0 ;i<getChildCount();i++){
                 View child = getChildAt(i);
                 if  (isEventWithinView(e, child)) {
                     if (mOnItemClicked !=  null ){
                         mOnItemClicked.onItemClick(HorizontalListView. this , child, mLeftViewIndex +  1  + i, mAdapter.getItemId( mLeftViewIndex +  1  + i ));
                     }
                     if (mOnItemSelected !=  null ){
                         mOnItemSelected.onItemSelected(HorizontalListView. this , child, mLeftViewIndex +  1  + i, mAdapter.getItemId( mLeftViewIndex +  1  + i ));
                     }
                     break ;
                 }
                              
             }
             return  true ;
         }
                      
         @Override
         public  void  onLongPress(MotionEvent e) {
             int  childCount = getChildCount();
             for  ( int  i =  0 ; i < childCount; i++) {
                 View child = getChildAt(i);
                 if  (isEventWithinView(e, child)) {
                     if  (mOnItemLongClicked !=  null ) {
                         mOnItemLongClicked.onItemLongClick(HorizontalListView. this , child, mLeftViewIndex +  1  + i, mAdapter.getItemId(mLeftViewIndex +  1  + i));
                     }
                     break ;
                 }
             }
         }
         private  boolean  isEventWithinView(MotionEvent e, View child) {
             Rect viewRect =  new  Rect();
             int [] childPosition =  new  int [ 2 ];
             child.getLocationOnScreen(childPosition);
             int  left = childPosition[ 0 ];
             int  right = left + child.getWidth();
             int  top = childPosition[ 1 ];
             int  bottom = top + child.getHeight();
             viewRect.set(left, top, right, bottom);
             return  viewRect.contains(( int ) e.getRawX(), ( int ) e.getRawY());
         }
     };
                  
}















本文转自 glblong 51CTO博客,原文链接:http://blog.51cto.com/glblong/1307725,如需转载请自行联系原作者

目录
相关文章
|
9月前
|
API Android开发 开发者
Android UI设计: 什么是RecyclerView?为什么它比ListView更好?
Android UI设计: 什么是RecyclerView?为什么它比ListView更好?
120 2
|
9月前
|
XML Android开发 数据安全/隐私保护
Android 自定义开源库 EasyView
Android 自定义开源库 EasyView
119 0
|
6月前
|
监控 Java API
Android经典实战之OkDownload:一个经典强大的文件下载开源库,支持断点续传
本文介绍的 OkDownload 是一个专为 Android 设计的开源下载框架,支持多线程下载、断点续传和任务队列管理等功能,具备可靠性、灵活性和高性能特点。它提供了多种配置选项和监听器,便于开发者集成和扩展。尽管已多年未更新,但依然适用于大多数文件下载需求。
522 1
|
9月前
|
XML Java Android开发
Android Studio App入门之列表视图ListView的讲解及实战(附源码 超详细必看)
Android Studio App入门之列表视图ListView的讲解及实战(附源码 超详细必看)
812 1
|
8月前
|
API Android开发 开发者
`RecyclerView`是Android API 21引入的UI组件,用于替代ListView和GridView
【6月更文挑战第26天】`RecyclerView`是Android API 21引入的UI组件,用于替代ListView和GridView。它提供高效的数据视图复用,优化的布局管理,支持多种布局(如线性、网格),并解耦数据、适配器和视图。RecyclerView的灵活性、性能(如局部刷新和动画支持)和扩展性使其成为现代Android开发的首选,特别是在处理大规模数据集时。
104 2
|
8月前
|
前端开发 API Android开发
25. 【Android教程】列表控件 ListView
25. 【Android教程】列表控件 ListView
291 2
|
9月前
|
XML Java Android开发
如何美化android程序:自定义ListView背景
如何美化android程序:自定义ListView背景
89 2
|
8月前
|
存储 API 开发工具
kotlin安卓开发,如何获取设备的唯一id, 有哪些开源库
在Kotlin的Android开发中,获取设备唯一ID的方法包括不稳定的ANDROID_ID、需要权限的IMEI、使用UUID与SharedPreference结合,以及考虑隐私的Firebase Installations ID和Advertising ID。由于隐私问题和Google Play政策,IMEI和ANDROID_ID不推荐作为长期唯一标识。推荐使用UUID(首次安装时生成并存储),或在涉及广告时使用Advertising ID(需用户同意),而Firebase Installations ID则提供了一种合规的设备标识选项。在选择方法时,必须遵守隐私指南和政策。
|
9月前
|
XML 编解码 Java
Android控件之高级控件——ListView、cardView、屏幕适配
Android控件之高级控件——ListView、cardView、屏幕适配
101 0
|
XML Android开发 数据格式
安卓-无敌解决ListView添加标题头无法正常显示的问题(歪门邪道)
安卓-无敌解决ListView添加标题头无法正常显示的问题(歪门邪道)
96 0

热门文章

最新文章

  • 1
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 2
    Android历史版本与APK文件结构
  • 3
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 4
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 10
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
  • 1
    android FragmentManager 删除所有Fragment 重建
    15
  • 2
    Android实战经验之Kotlin中快速实现MVI架构
    21
  • 3
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    24
  • 4
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    39
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    122
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    40
  • 7
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    55
  • 8
    Android历史版本与APK文件结构
    148
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    46
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    40