这期内容当中小编将会给大家带来有关如何在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>
上述就是小编为大家分享的如何在android中使用水平循环滚动控件了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。