• Android:图片滚轮


    Android客户端中,我们经常要实现图片滚轮的效果。

    实现的方式就是自定义相关View,这里主要是包括两个类:ImageScroller和PagerIndicator。

    PagerIndicator类:

    public class PagerIndicator extends ViewGroup {
        
        public static int mMaxTotalItems = 9;
        private int mTotalItems;
        private int mCurrentItem;
        private int mDotDrawableId;//滑动的图片
        
        public PagerIndicator(Context context, AttributeSet attrs) {
            super(context, attrs);
            initPager();
        }
    
        public PagerIndicator(Context context) {
            super(context);
            initPager();
        }
        
        private void initPager(){
            setFocusable(false);
            setWillNotDraw(false);
            mDotDrawableId=R.drawable.pager_dots;
        }
        
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            if(mTotalItems<=0) return;
            createLayout();
        }
        
        private void updateLayout(){
            for(int i=0;i<getChildCount();i++){
                final ImageView img=(ImageView) getChildAt(i);
                TransitionDrawable tmp=(TransitionDrawable)img.getDrawable();
                if(i==mCurrentItem){
                    tmp.startTransition(0);
                }else{
                    tmp.resetTransition();
                }
            }
        }
        
        private void createLayout(){
            detachAllViewsFromParent();
            
            int dotWidth=getResources().getDrawable(mDotDrawableId).getIntrinsicWidth();
            int separation=9;
            
            int marginLeft=((getWidth())/2)-(((mTotalItems*dotWidth)/2)+(((mTotalItems-1)*separation)/2));
            int marginTop=((getHeight())/2)-(dotWidth/2);
            for(int i=0;i<mTotalItems;i++){
                ImageView dot=new ImageView(getContext());
                
                TransitionDrawable td=(TransitionDrawable)getResources().getDrawable(mDotDrawableId);
                
                td.setCrossFadeEnabled(true);
                dot.setImageDrawable(td);
                ViewGroup.LayoutParams p;
                p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                        ViewGroup.LayoutParams.FILL_PARENT);
                dot.setLayoutParams(p);
                int childHeightSpec = getChildMeasureSpec(
                        MeasureSpec.makeMeasureSpec(dotWidth, MeasureSpec.UNSPECIFIED), 0, p.height);
                int childWidthSpec = getChildMeasureSpec(
                        MeasureSpec.makeMeasureSpec(dotWidth, MeasureSpec.EXACTLY), 0, p.width);
                dot.measure(childWidthSpec, childHeightSpec);
                
                int left=marginLeft+(i*(dotWidth+separation));
                
                dot.layout(left, marginTop, left+dotWidth,marginTop+dotWidth );
                addViewInLayout(dot, getChildCount(), p, true);
                if(i==mCurrentItem){
                    TransitionDrawable tmp=(TransitionDrawable)dot.getDrawable();
                    tmp.startTransition(0);
                }
            }
            postInvalidate();
        }
        
        public int getTotalItems() {
            return mTotalItems;
        }
    
        public void setTotalItems(int totalItems) {
            if(totalItems!=mTotalItems){
                
                if(totalItems <= mMaxTotalItems){
                    mTotalItems = totalItems;
                } else {
                    mTotalItems = mMaxTotalItems;
                }
                
                createLayout();
            }
        }
    
        public int getCurrentItem() {
            return mCurrentItem;
        }
    
        public void setCurrentItem(int currentItem) {
            
            if(currentItem!=mCurrentItem){
                mCurrentItem = currentItem;
                updateLayout();
            }
        }
        
        /**
         * 向左翻页
         * @param pageLeave 在最左边还有多少页没显示
         * @return 左边超出的页数
         */
        public void rollLeft(int currentPage, int totalChild){
            
            if(mCurrentItem == 0){
                setCurrentItem(Math.min(currentPage, mTotalItems / 2) - 1);
            } else {
                setCurrentItem(Math.max(0, mCurrentItem - 1));
            }
        }
        
        /**
         * 向右翻页
         * @param pageLeave 在最右边还有多少页没显示
         * @return 右边超出的页数
         */
        public void rollRight(int currentPage, int totalChild){
    
            if(mCurrentItem == (mTotalItems - 1)){
                 final int pageLeave = totalChild - currentPage - 1;
                 if(pageLeave < mTotalItems / 2){
                     setCurrentItem(mTotalItems - pageLeave);
                 } else {
                    setCurrentItem(mTotalItems / 2);
                 }
            } else {
                setCurrentItem(Math.min((mCurrentItem + 1), mTotalItems - 1));
            }
        }
    }

    ImageScroller类:

    public class ImageScroller extends ViewGroup {
        
        private static String TAG = ImageScroller.class.getSimpleName();
        
        private static final int INVALID_SCREEN = -1;
        private static final int SNAP_VELOCITY = 800;
        private final static int TOUCH_STATE_REST = 0;
        private final static int TOUCH_STATE_SCROLLING = 1;
        
        private boolean mTapChange;
        
        private PagerIndicator mIndicator;
        
        private int currentScreen;
        private int nextScreen = INVALID_SCREEN;
        private int lastMotionX;
        private int lastMotionY;
        
        private int touchState = TOUCH_STATE_REST;
        private int touchSlop;
    
        private Map<String, SoftReference<Bitmap>> mCacheBitmap;
        private Set<ImageView> mMissingView;
        private ExecutorService mExecutorService;
    
        private VelocityTracker mVelocityTracker;
        private Scroller scroller;
        private Resources mResources;
        private static final int FETCH_IMAGE_BITMAP = 1;
        
        private boolean mSyncLoad = false;        //是否需异步加载
    
        public ImageScroller(Context context) {
            this(context, null);
        }
    
        public ImageScroller(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ImageScroller(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            
            touchSlop = ViewConfiguration.getTouchSlop();//用户拖动时应该的距离
            scroller = new Scroller(getContext());
            mResources = getResources();
            mCacheBitmap = new HashMap<String, SoftReference<Bitmap>>();
            mMissingView = new HashSet<ImageView>();
            mExecutorService = Executors.newFixedThreadPool(3);//线程池
        }
    
        public void setPageIndicator(PagerIndicator indicator){
            mIndicator = indicator;
        }
        
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            
            final int count = getChildCount();
            for (int i = 0; i < count; i++) {
                getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    
        @Override
        protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
            int childLeft = 0;
            final int count = getChildCount();
            
            for (int i = 0; i < count; i++) {
                final View child = getChildAt(i);
                if (child.getVisibility() != View.GONE) {
                    final int childWidth = child.getMeasuredWidth();
                    final int childHeight = child.getMeasuredHeight();
                    child.layout(childLeft, 0, childLeft + childWidth,
                            child.getMeasuredHeight());
                    childLeft += childWidth;
                }
            }
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            final int action = ev.getAction();
            if ((action == MotionEvent.ACTION_MOVE) && (touchState != TOUCH_STATE_REST)) {
                return true;
            }
    
            final float x = ev.getX();
            final float y = ev.getY();
    
            switch (action) {
            case MotionEvent.ACTION_MOVE:
                final int xDiff = (int) Math.abs(x - lastMotionX);
                final int yDiff = (int) Math.abs(y - lastMotionY);
                boolean xMoved = xDiff > touchSlop;
                boolean yMoved = yDiff > touchSlop;
                
                if(xMoved || yMoved){
                    if (xMoved) {
                        touchState = TOUCH_STATE_SCROLLING;
                    }
                }
                
                break;
    
            case MotionEvent.ACTION_DOWN:
                lastMotionX = (int) x;
                touchState = scroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
                break;
    
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                touchState = TOUCH_STATE_REST;
                break;
            }
            return touchState != TOUCH_STATE_REST;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            
            if (mVelocityTracker == null) {
                mVelocityTracker = VelocityTracker.obtain();
            }
            mVelocityTracker.addMovement(ev);
    
            final int action = ev.getAction();
            final float x = ev.getX();
    
            switch (action) {
            case MotionEvent.ACTION_DOWN:
    
                if (!scroller.isFinished()) {
                    scroller.abortAnimation();
                }
                lastMotionX = (int) x;
                break;
            case MotionEvent.ACTION_MOVE:
                
                if (touchState == TOUCH_STATE_SCROLLING) {
                    final int deltaX = (int) (lastMotionX - x);
                    lastMotionX = (int) x;
                    
                    if (deltaX < 0 && getScrollX() > 0) {
                        
                        scrollBy(Math.max(-getScrollX(), deltaX), 0);
                        
                    } else if (deltaX > 0) {
                        final int availableToScroll = getChildAt(getChildCount() - 1).getRight() - getScrollX() - getWidth();
                        if (availableToScroll > 0) {
                            scrollBy(Math.min(availableToScroll, deltaX), 0);
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                
                if (touchState == TOUCH_STATE_SCROLLING) {
                    final VelocityTracker velocityTracker = mVelocityTracker;
                    velocityTracker.computeCurrentVelocity(1000);
                    int velocityX = (int) velocityTracker.getXVelocity();
    
                    if (velocityX > SNAP_VELOCITY && currentScreen > 0) {
                        scrollToScreen(currentScreen - 1);
                    } else if (velocityX < -SNAP_VELOCITY && currentScreen < getChildCount() - 1) {
                        scrollToScreen(currentScreen + 1);
                    } else {
                        snapToDestination();
                    }
    
                    if (mVelocityTracker != null) {
                        mVelocityTracker.recycle();
                        mVelocityTracker = null;
                    }
                }
                touchState = TOUCH_STATE_REST;
                break;
            case MotionEvent.ACTION_CANCEL:
                touchState = TOUCH_STATE_REST;
                break;
            }
    
            return true;
        }
        
        private void snapToDestination() {
            final int screenWidth = getWidth();
            final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;
            scrollToScreen(whichScreen);
        }
        
        public void scrollToScreen(int whichScreen) {
            boolean changingScreens = whichScreen != currentScreen;
            
            nextScreen = whichScreen;
            
            View focusedChild = getFocusedChild();
            if (focusedChild != null && changingScreens && focusedChild == getChildAt(currentScreen)) {
              focusedChild.clearFocus();
            }
            
            
            final int newX = whichScreen * getWidth();
            final int delta = newX - getScrollX();
            scroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);
            invalidate();    
        }
        
        public void scrollToScreen(int whichScreen, int duration) {
            boolean changingScreens = whichScreen != currentScreen;
            
            nextScreen = whichScreen;
            
            View focusedChild = getFocusedChild();
            if (focusedChild != null && changingScreens && focusedChild == getChildAt(currentScreen)) {
              focusedChild.clearFocus();
            }
            
            
            final int newX = whichScreen * getWidth();
            final int delta = newX - getScrollX();
            scroller.startScroll(getScrollX(), 0, delta, 0, duration);
            invalidate();    
        }
        
        @Override
        public void computeScroll() {
    
            if (scroller.computeScrollOffset()) {
                scrollTo(scroller.getCurrX(), scroller.getCurrY());
                postInvalidate();
            } else if (nextScreen != INVALID_SCREEN) {
                
                if(mTapChange){
                    mTapChange = false;
                } else {
                    if(mIndicator != null && currentScreen < nextScreen){
                        
                        mIndicator.rollRight(currentScreen, getChildCount());
                    } else if (mIndicator != null && currentScreen > nextScreen){
    
                        mIndicator.rollLeft(currentScreen, getChildCount());
                    }
                }
                
                currentScreen = nextScreen;
                nextScreen = INVALID_SCREEN;
                
                if(mSyncLoad){
                    ImageView child = (ImageView) getChildAt(currentScreen);
                    if(child == null){
                        return;
                    }
                    
                    Movie movie = (Movie) child.getTag();
                    if(movie != null){
                        
                        SoftReference<Bitmap> ref = mCacheBitmap.get(movie.getImage().getBigImage());
                        if(ref != null){
                            Bitmap bitmap = ref.get();
                            if(bitmap != null) {
                                child.setImageBitmap(bitmap);
                            }
                        } else {
                            fetchBitmapFromCache(child, movie);
                        }
                    }
                }
            }
        }
        
        private void fetchBitmapFromCache(final ImageView child, final Movie coupon) {
            mMissingView.add(child);
            
            mExecutorService.execute(new Runnable() {
                
                @Override
                public void run() {
                    
                    String imagePath = coupon.getImage().getBigImage();
                    Bitmap bitmap = loadBitmapFromUri(imagePath);
                    if(bitmap != null){
                        bitmap = ImageUtil.getRoundedCornerBitmap(bitmap, 10);
                        mCacheBitmap.put(imagePath, new SoftReference<Bitmap>(bitmap));
                        
                        Message message = new Message();
                        message.what = FETCH_IMAGE_BITMAP;
                        message.obj = child;
                        handler.sendMessage(message);
                    }
                }
            });
        }
        
        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch(msg.what){
                case FETCH_IMAGE_BITMAP:
                    
                    ImageView view = (ImageView) msg.obj;
                    Movie movie = (Movie) view.getTag();
                    if(view == null || movie == null){
                        break;
                    }
                    
                    SoftReference<Bitmap> ref = mCacheBitmap.get(movie.getImage().getBigImage());
                    if(ref != null){
                        Bitmap bitmap = ref.get();
                        if(bitmap != null){
                            view.setImageBitmap(bitmap);
                            mMissingView.remove(view);
                        }
                    } else {
                        mCacheBitmap.remove(movie.getId());
                    }
                    break;
                }
            }
        };
        
        private Bitmap loadBitmapFromUri(String path){
            Bitmap bitmap = null;
            URL url;
            InputStream i = null;
            try {
                url = new URL(path);
                i = (InputStream) url.getContent();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            bitmap = BitmapFactory.decodeStream(i);
            return bitmap;
        }
        
        public void setTapChange(boolean value){
            mTapChange = value;
        }
        
        public void setSyncLoad(boolean syncLoad) {
            mSyncLoad = syncLoad;
        }
    }

     

  • 相关阅读:
    【BZOJ 3090】 树形DP
    【BZOJ 2323】 2323: [ZJOI2011]细胞 (DP+矩阵乘法+快速幂*)
    【BZOJ 1019】 1019: [SHOI2008]汉诺塔 (DP?)
    【BZOJ 3294】 3294: [Cqoi2011]放棋子 (DP+组合数学+容斥原理)
    【BZOJ 3566】 3566: [SHOI2014]概率充电器 (概率树形DP)
    【BZOJ 2121】 (字符串DP,区间DP)
    【BZOJ 4305】 4305: 数列的GCD (数论)
    【UOJ 179】 #179. 线性规划 (单纯形法)
    【BZOJ 4568】 4568: [Scoi2016]幸运数字 (线性基+树链剖分+线段树)
    【BZOJ 4027】 4027: [HEOI2015]兔子与樱花 (贪心)
  • 原文地址:https://www.cnblogs.com/gongcb/p/2494502.html
Copyright © 2020-2023  润新知