zoukankan      html  css  js  c++  java
  • 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>
    <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>
    



  • 相关阅读:
    SpringBoot启动里的细节问题
    SpringBoot运行过程从SpringApplication开始解读
    SpringBoot应用启动流程
    SpringBoot上传相关配置
    planUML时序图
    JAVA设计模式--单例模式
    中国云运营商横向对比——IaaS服务对标
    ansible api2.0 多进程执行不同的playbook
    自动化运维平台搭建
    django-将数据库数据转换成JSON格式(ORM和SQL两种情况)
  • 原文地址:https://www.cnblogs.com/riskyer/p/3306400.html
Copyright © 2011-2022 走看看