前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >android水平循环滚动控件使用详解

android水平循环滚动控件使用详解

作者头像
砸漏
发布2020-10-30 01:01:50
2.3K0
发布2020-10-30 01:01:50
举报
文章被收录于专栏:恩蓝脚本恩蓝脚本恩蓝脚本

本文实例为大家分享了android水平循环滚动控件的具体代码,供大家参考,具体内容如下

CycleScrollView.java

package com.example.test; 
import android.content.Context; 
import android.graphics.Rect; 
import android.os.Handler; 
import android.util.AttributeSet; 
import android.view.GestureDetector; 
import android.view.GestureDetector.OnGestureListener; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.Scroller; 
@SuppressWarnings("deprecation") 
public class CycleScrollView<T  extends ViewGroup implements OnGestureListener { 
static final String TAG = "CycleScrollView"; 
Context mContext; 
/** 
* Scroll velocity. 
*/ 
public static final long SCROLL_VELOCITY = 50; 
/** 
* Scroll offset. 
*/ 
public static final int SCROLL_OFFSET = -1; 
/** 
* Touch delay. 
*/ 
public static final long TOUCH_DELAYMILLIS = 2000; 
/** 
* Fling duration. 
*/ 
public static final int FLING_DURATION = 2000; 
/** 
* Filing max velocity x. 
*/ 
public static final int MAX_VELOCITY_X = 1000; 
private GestureDetector detector; 
private Handler mHandler; 
private Scroller mScroller; 
/** 
* Callback interface adapter and OnItemClick. 
*/ 
private CycleScrollAdapter<T  mAdapter; 
private OnItemClickListener mOnItemClickListener; 
/** 
* Scroll index 
*/ 
private int mPreIndex; 
private int mCurrentIndex; 
private int mNextIndex; 
private View mCurrentView; 
private View mPreView; 
private View mNextView; 
private float mLastMotionX; 
// The reLayout is false can not invoke onLayout. 
private boolean reLayout = false; 
// If the item count more than screen that can scroll. 
private boolean canScroll = false; 
// A flag for switch current view. 
private boolean mCurrentViewAtLeft = true; 
// Fling distance. 
private int mFlingX = 0; 
private boolean isMoveAction = false; 
private int defaultItemY = 10; 
private int maxItemCount = 7; 
private int initItemX = 20; 
/** 
* The screen width. 
*/ 
private int screenWidth; 
/** 
* Item view height. 
*/ 
private int itemHeight; 
/** 
* Item view width. 
*/ 
private int itemWidth; 
/** 
* Item view layout x. 
*/ 
private int itemX = getInitItemX(); 
/** 
* Item view layout y. 
*/ 
private int itemY = defaultItemY; 
// Auto scroll view task. 
private final Runnable mScrollTask = new Runnable() { 
@Override 
public void run() { 
if (canScroll) { 
scrollView(SCROLL_OFFSET); 
mHandler.postDelayed(this, SCROLL_VELOCITY);// Loop self. 
} 
} 
}; 
public CycleScrollView(Context context) { 
super(context); 
onCreate(context); 
} 
public CycleScrollView(Context context, AttributeSet attrs) { 
super(context, attrs); 
onCreate(context); 
} 
public CycleScrollView(Context context, AttributeSet attrs, int defStyle) { 
super(context, attrs, defStyle); 
onCreate(context); 
} 
private void onCreate(Context context) { 
mContext = context; 
detector = new GestureDetector(this); 
mHandler = new Handler(); 
mScroller = new Scroller(context); 
} 
/** 
* Create scroll index. 
*/ 
public void createIndex() { 
if (canScroll) { 
mPreIndex = maxItemCount - 1; 
mCurrentIndex = 0; 
mNextIndex = 1; 
mPreView = getChildAt(mPreIndex); 
mCurrentView = getChildAt(mCurrentIndex); 
mNextView = getChildAt(mNextIndex); 
} 
} 
/** 
* Set item click callback. 
* 
* @param onItemClickListener 
*   The callback 
*/ 
public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 
mOnItemClickListener = onItemClickListener; 
} 
/** 
* Set itemAdapter for addItem and bindItem. 
* 
* @param itemAdapter 
*/ 
public void setAdapter(CycleScrollAdapter<T  adapter) { 
mAdapter = adapter; 
} 
/** 
* Start auto scroll. 
*/ 
public void startScroll() { 
if (canScroll) { 
mHandler.post(mScrollTask); 
} 
} 
/** 
* Stop auto scroll and filing scroll task. 
*/ 
public void stopScroll() { 
mHandler.removeCallbacks(mScrollTask); 
} 
/** 
* Delay start auto scroll task. 
*/ 
public void delayStartScroll() { 
if (canScroll) { 
mHandler.postDelayed(mScrollTask, TOUCH_DELAYMILLIS); 
} 
} 
@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
int count = this.getChildCount(); 
for (int i = 0; i < count; i++) { 
View child = this.getChildAt(i); 
child.measure(widthMeasureSpec, heightMeasureSpec); 
} 
} 
@Override 
protected void onLayout(boolean changed, int l, int t, int r, int b) { 
/** 
* On layout set the child view layout by x y width and height. 
*/ 
if (reLayout) {// Run one times. 
for (int i = 0; i < getChildCount(); i++) { 
View child = this.getChildAt(i); 
child.setVisibility(View.VISIBLE); 
child.layout(itemX, getItemY(), itemX + getItemWidth(), 
getItemY() + getItemHeight()); 
itemX += getItemMargin(); 
} 
reLayout = !reLayout; 
} 
} 
/** 
* When fling view run the fling task scroll view. 
*/ 
@Override 
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
float velocityY) { 
if (e1 == null || e2 == null) { 
return false; 
} 
// When deltaX and velocityX not good return false. 
if (Math.abs(velocityX) < MAX_VELOCITY_X) { 
return false; 
} 
// Get the delta x. 
float deltaX = (e1.getX() - e2.getX()); 
/** 
* If can fling stop other scroll task at first , delay the task after 
* fling. 
*/ 
mHandler.removeCallbacks(mScrollTask); 
if (canScroll) { 
mHandler.postDelayed(mScrollTask, TOUCH_DELAYMILLIS 
+ FLING_DURATION - 1000); 
} 
/** 
* The flingX is fling distance. 
*/ 
mFlingX = (int) deltaX; 
// Start scroll with fling x. 
mScroller.startScroll(0, 0, mFlingX, 0, FLING_DURATION); 
return false; 
} 
@Override 
public void computeScroll() { 
if (canScroll && mScroller.computeScrollOffset()) { 
/** 
* The Scroller.getCurrX() approach mFlingX , the deltaX more and 
* more small. 
*/ 
int deltaX = mFlingX - mScroller.getCurrX(); 
scrollView(-deltaX / 10); 
postInvalidate(); 
} 
} 
/** 
* When touch event is move scroll child view. 
*/ 
@Override 
public boolean onTouchEvent(MotionEvent ev) { 
// Get event x,y at parent view. 
final float x = ev.getX(); 
/** 
* Get event x,y at screen. 
*/ 
final int rawX = (int) ev.getRawX(); 
final int rawY = (int) ev.getRawY(); 
switch (ev.getAction()) { 
case MotionEvent.ACTION_DOWN: 
// Reset isMoveAction. 
isMoveAction = false; 
// Get motionX. 
mLastMotionX = x; 
break; 
case MotionEvent.ACTION_MOVE: 
// When action move set isMoveAction true. 
isMoveAction = true; 
// Only support one pointer. 
if (ev.getPointerCount() == 1) { 
// Compute delta X. 
int deltaX = 0; 
deltaX = (int) (x - mLastMotionX); 
mLastMotionX = x; 
// When canScroll is true, scrollView width deltaX. 
if (canScroll) { 
scrollView(deltaX); 
} 
} 
break; 
case MotionEvent.ACTION_UP: 
/** 
* If not move find click item and invoke click event. 
*/ 
if (!isMoveAction) { 
View view = getClickItem(rawX, rawY); 
if (view != null) { 
mOnItemClickListener.onItemClick(Integer.valueOf(view 
.getTag().toString())); 
} 
} 
break; 
} 
return this.detector.onTouchEvent(ev); 
} 
/** 
* Get click item view by rawX and rawY. 
* @param rawX the x at screen. 
* @param rawY the y at screen. 
* @return the click item view. 
*/ 
private View getClickItem(final int rawX, final int rawY) { 
for (int i = 0; i < getChildCount(); i++) { 
View child = getChildAt(i); 
// Get item view rect. 
Rect rect = new Rect(); 
child.getGlobalVisibleRect(rect); 
// If click point on the item view, invoke the click event. 
if (rect.contains(rawX, rawY)) { 
return child; 
} 
} 
return null; 
} 
/** 
* Scroll view by delta x. 
* 
* @param deltaX 
*   The scroll distance. 
*/ 
private void scrollView(int deltaX) { 
// Move child view by deltaX. 
moveChildView(deltaX); 
// After move change index. 
if (deltaX < 0) {// move left 
// If current at right switch current view to left. 
switchCurrentViewToLeft(); 
// change previous current next index. 
moveToNext(); 
} else {// move right 
// If current at left switch current view to right. 
switchCurrentViewToRight(); 
// change previous current next index. 
moveToPre(); 
} 
invalidate(); 
} 
/** 
* Move view by delta x. 
* 
* @param deltaX 
*   The move distance. 
*/ 
private void moveChildView(int deltaX) { 
for (int i = 0; i < getChildCount(); i++) { 
View child = getChildAt(i); 
child.layout(child.getLeft() + deltaX, child.getTop(), 
child.getRight() + deltaX, child.getBottom()); 
} 
} 
/** 
* Current event is move to left, if current view at right switch current 
* view to left. 
*/ 
private void switchCurrentViewToLeft() { 
if (!mCurrentViewAtLeft) { 
mPreIndex = mCurrentIndex; 
mCurrentIndex = mNextIndex; 
mNextIndex++; 
if (mNextIndex   maxItemCount - 1) { 
mNextIndex = 0; 
} 
mCurrentView = getChildAt(mCurrentIndex); 
mPreView = getChildAt(mPreIndex); 
mNextView = getChildAt(mNextIndex); 
mCurrentViewAtLeft = !mCurrentViewAtLeft; 
} 
} 
/** 
* Current event is move to right, if current view at left switch current 
* view to right. 
*/ 
private void switchCurrentViewToRight() { 
if (mCurrentViewAtLeft) { 
mNextIndex = mCurrentIndex; 
mCurrentIndex = mPreIndex; 
mPreIndex--; 
if (mPreIndex < 0) { 
mPreIndex = maxItemCount - 1; 
} 
mCurrentView = getChildAt(mCurrentIndex); 
mPreView = getChildAt(mPreIndex); 
mNextView = getChildAt(mNextIndex); 
mCurrentViewAtLeft = !mCurrentViewAtLeft; 
} 
} 
/** 
* Current event is move to left,if current view move out of screen move the 
* current view to right and reBind the item change index. 
*/ 
private void moveToNext() { 
if (mCurrentView.getRight() < 0) { 
mCurrentView.layout(mPreView.getLeft() + getItemMargin(), 
getItemY(), mPreView.getLeft() + getItemMargin() 
+ getItemWidth(), getItemY() + getItemHeight()); 
if (mCurrentView.getTag() != null) { 
int listIndex = (Integer) mCurrentView.getTag(); 
int index = (listIndex + maxItemCount) % mAdapter.getCount(); 
mAdapter.bindView(mCurrentView, mAdapter.get(index)); 
mCurrentView.setTag(index); 
} 
mPreIndex = mCurrentIndex; 
mCurrentIndex = mNextIndex; 
mNextIndex++; 
if (mNextIndex   maxItemCount - 1) { 
mNextIndex = 0; 
} 
mCurrentView = getChildAt(mCurrentIndex); 
mPreView = getChildAt(mPreIndex); 
mNextView = getChildAt(mNextIndex); 
moveToNext(); 
} 
} 
/** 
* Current event is move to right,if current view move out of screen move 
* the current view to left and reBind the item change index. 
*/ 
private void moveToPre() { 
if (mCurrentView.getLeft()   getScreenWidth()) { 
mCurrentView.layout(mNextView.getLeft() - getItemMargin(), 
getItemY(), mNextView.getLeft() - getItemMargin() 
+ getItemWidth(), getItemY() + getItemHeight()); 
if (mCurrentView.getTag() != null) { 
int listIndex = (Integer) mCurrentView.getTag(); 
int index = (listIndex - maxItemCount + mAdapter.getCount()) 
% mAdapter.getCount(); 
mAdapter.bindView(mCurrentView, mAdapter.get(index)); 
mCurrentView.setTag(index); 
} 
mNextIndex = mCurrentIndex; 
mCurrentIndex = mPreIndex; 
mPreIndex--; 
if (mPreIndex < 0) { 
mPreIndex = maxItemCount - 1; 
} 
mCurrentView = getChildAt(mCurrentIndex); 
mPreView = getChildAt(mPreIndex); 
mNextView = getChildAt(mNextIndex); 
moveToPre(); 
} 
} 
@Override 
public boolean onDown(MotionEvent e) { 
return true; 
} 
@Override 
public void onShowPress(MotionEvent e) { 
} 
@Override 
public boolean onSingleTapUp(MotionEvent e) { 
return false; 
} 
@Override 
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, 
float distanceY) { 
return false; 
} 
@Override 
public void onLongPress(MotionEvent e) { 
} 
public int getMaxItemCount() { 
return maxItemCount; 
} 
public void setMaxItemCount(int maxItemCount) { 
this.maxItemCount = maxItemCount; 
} 
public void setReLayout(boolean reLayout) { 
this.reLayout = reLayout; 
} 
public void setCanScroll(boolean canScroll) { 
this.canScroll = canScroll; 
} 
public int getItemX() { 
return itemX; 
} 
public void setItemX(int itemX) { 
this.itemX = itemX; 
} 
public int getItemY() { 
return itemY; 
} 
public void setItemY(int itemY) { 
this.itemY = itemY; 
} 
public int getItemWidth() { 
return itemWidth; 
} 
public void setItemWidth(int itemWidth) { 
this.itemWidth = itemWidth; 
} 
public int getItemHeight() { 
return itemHeight; 
} 
public void setItemHeight(int itemHeight) { 
this.itemHeight = itemHeight; 
} 
public int getItemMargin() { 
return (screenWidth - itemWidth * (maxItemCount - 1) - initItemX * 2)/(maxItemCount - 2) + itemWidth; 
} 
public int getScreenWidth() { 
return screenWidth; 
} 
public void setScreenWidth(int screenWidth) { 
this.screenWidth = screenWidth; 
} 
public int getInitItemX() { 
return initItemX; 
} 
public void setInitItemX(int initItemX) { 
this.initItemX = initItemX; 
} 
/** 
* The interface for item click callback. 
*/ 
interface OnItemClickListener { 
public boolean onItemClick(int position); 
} 
} 

CycleScrollAdapter.java

package com.example.test; 
import java.util.List; 
import android.app.Activity; 
import android.content.Context; 
import android.util.DisplayMetrics; 
import android.view.View; 
public abstract class CycleScrollAdapter<T  { 
private List<T  list; 
private CycleScrollView<T  mCycleScrollView; 
Context mContext; 
/** 
* Initial CycleScrollAdapter bind list to view. 
* 
* @param list 
*   The list data. 
* @param cycleScrollView 
*   The CycleScrollView. 
* @param context 
*   The Context. 
*/ 
public CycleScrollAdapter(List<T  list, CycleScrollView<T  cycleScrollView, 
Context context) { 
this.list = list; 
mContext = context; 
mCycleScrollView = cycleScrollView; 
mCycleScrollView.setAdapter(this); 
GetScreenWidthPixels(); 
initView(list); 
} 
/** 
* Get screen width pixels. 
*/ 
private void GetScreenWidthPixels() { 
DisplayMetrics dm = new DisplayMetrics(); 
Activity a = (Activity) mContext; 
a.getWindowManager().getDefaultDisplay().getMetrics(dm); 
mCycleScrollView.setScreenWidth(dm.widthPixels); 
} 
/** 
* Bind list to view. 
* 
* @param list 
*   The list data. 
*/ 
protected void initView(List<T  list) { 
if (list == null || list.size() == 0) { 
return; 
} 
// Clear all view from ViewGroup at first. 
mCycleScrollView.removeAllViewsInLayout(); 
// Loop list. 
for (int i = 0; i < list.size(); i++) { 
/** 
* If list size more than MaxItemCount break the loop, only create 
* view count is MaxItemCount. 
*/ 
if (i == mCycleScrollView.getMaxItemCount()) { 
break; 
} 
/** 
* If list size less than MaxItemCount at the last loop reLayout 
* otherwise at the MaxItemCount index reLayout. 
*/ 
if (i == list.size() - 1 
|| i == mCycleScrollView.getMaxItemCount() - 1) { 
mCycleScrollView.setItemX(mCycleScrollView.getInitItemX()); 
mCycleScrollView.setReLayout(true); 
} 
add(list.get(i), i); 
} 
/** 
* If list count more than MaxItemCount the view can scroll otherwise 
* can not scroll. 
*/ 
if (list.size()  = mCycleScrollView.getMaxItemCount()) { 
mCycleScrollView.setCanScroll(true); 
} else { 
mCycleScrollView.setCanScroll(false); 
} 
/** 
* If list count more than MaxItemCount reBuild index. 
*/ 
mCycleScrollView.createIndex(); 
} 
/** 
* Get list size. 
* 
* @return The list size. 
*/ 
public int getCount() { 
return list.size(); 
} 
/** 
* Returns the element at the specified location in this 
* 
* @param index 
*   the index of the element to return. 
* @return the element at the specified location. 
*/ 
public T get(int index) { 
return list.get(index); 
} 
/** 
* Adds the specified object at the end of this and refresh view. 
* 
* @param t 
*   the object to add. 
*/ 
public void addItem(T t) { 
list.add(t); 
initView(list); 
} 
/** 
* Removes the first occurrence of the specified object from this and 
* refresh view. 
* 
* @param t 
*   the object to remove. 
*/ 
public void removeItem(T t) { 
list.remove(t); 
initView(list); 
} 
/** 
* Add the specified view to the index. 
* 
* @param t 
*   The data to add. 
* @param index 
*   the index. 
*/ 
private void add(T t, int index) { 
View view = getView(t); 
ComputeItemSize(view); 
mCycleScrollView.addView(view); 
view.setTag(index); 
} 
/** 
* If item size is null compute item size. 
* 
* @param view 
*   the item view. 
*/ 
private void ComputeItemSize(View view) { 
if (mCycleScrollView.getItemWidth() == 0 
|| mCycleScrollView.getItemHeight() == 0) { 
int w = View.MeasureSpec.makeMeasureSpec(0, 
View.MeasureSpec.UNSPECIFIED); 
int h = View.MeasureSpec.makeMeasureSpec(0, 
View.MeasureSpec.UNSPECIFIED); 
view.measure(w, h); 
int height = view.getMeasuredHeight(); 
int width = view.getMeasuredWidth(); 
mCycleScrollView.setItemHeight(height); 
mCycleScrollView.setItemWidth(width); 
} 
} 
/** 
* Get item view. 
* 
* @param t 
*   the data need bind to view. 
* @return the view. 
*/ 
public abstract View getView(T t); 
/** 
* Bind the item to view. 
* 
* @param child 
*   the item view need bind. 
* @param t 
*   the item. 
*/ 
public abstract void bindView(View child, T t); 
} 

以上两个是核心类,下面是测试代码。

实现CycleScrollAdapter

AppCycleScrollAdapter.java绑定视图和应用数据

package com.example.test; 
import java.util.List; 
import android.content.Context; 
import android.content.pm.PackageInfo; 
import android.view.View; 
import android.widget.ImageView; 
import android.widget.TextView; 
public class AppCycleScrollAdapter extends CycleScrollAdapter<PackageInfo  { 
public AppCycleScrollAdapter(List<PackageInfo  list, 
CycleScrollView<PackageInfo  cycleScrollView, Context context) { 
super(list, cycleScrollView, context); 
} 
@Override 
protected void initView(List<PackageInfo  list) { 
super.initView(list); 
} 
@Override 
public void bindView(View child, PackageInfo pi) { 
ImageView image = (ImageView) child.findViewById(R.id.item_image); 
TextView text = (TextView) child.findViewById(R.id.item_text); 
image.setImageDrawable(pi.applicationInfo.loadIcon(mContext 
.getPackageManager())); 
text.setText(pi.applicationInfo.loadLabel(mContext.getPackageManager())); 
} 
@Override 
public View getView(PackageInfo pi) { 
View view = View.inflate(mContext, R.layout.view_item, null); 
// inflate APP icon view 
ImageView image = (ImageView) view.findViewById(R.id.item_image); 
// inflate APP name view 
TextView text = (TextView) view.findViewById(R.id.item_text); 
image.setImageDrawable(pi.applicationInfo.loadIcon(mContext 
.getPackageManager())); 
text.setText(pi.applicationInfo.loadLabel(mContext.getPackageManager())); 
return view; 
} 
} 

入口Activity

package com.example.test; 
import java.util.List; 
import android.app.Activity; 
import android.content.pm.PackageInfo; 
import android.os.Bundle; 
import android.view.Menu; 
public class MainActivity extends Activity{ 
private CycleScrollView<PackageInfo  mCycleScrollView; 
private AppCycleScrollAdapter mAdapter; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
mCycleScrollView = ((CycleScrollView<PackageInfo ) this.findViewById(R.id.cycle_scroll_view)); 
/** 
* Get APP list and sort by update time. 
*/ 
List<PackageInfo  list = this.getPackageManager() 
.getInstalledPackages(0); 
mAdapter = new AppCycleScrollAdapter(list, mCycleScrollView, this); 
} 
@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
getMenuInflater().inflate(R.menu.activity_main, menu); 
return true; 
} 
} 

布局文件

<?xml version="1.0" encoding="utf-8"?  
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
<ImageView 
android:id="@+id/item_image" 
android:layout_width="60dip" 
android:layout_height="60dip" 
android:layout_y="5dip" 
android:layout_x="10dip" 
/  
<TextView 
android:id="@+id/item_text" 
android:layout_width="80dip" 
android:layout_height="20dip" 
android:layout_y="65dip" 
android:layout_x="0dip" 
android:gravity="center_horizontal" /  
</AbsoluteLayout  
[java] view plain copy
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent"   
<TextView 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_centerHorizontal="true" 
android:layout_centerVertical="true" 
android:text="@string/hello_world" 
tools:context=".MainActivity" /  
<com.example.test.CycleScrollView 
android:id="@+id/cycle_scroll_view" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
android:background="#B9000000" 
/  
</RelativeLayout  

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档