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

     

  • 相关阅读:
    Security headers quick reference Learn more about headers that can keep your site safe and quickly look up the most important details.
    Missing dollar riddle
    Where Did the Other Dollar Go, Jeff?
    proteus 与 keil 联调
    cisco router nat
    router dhcp and dns listen
    配置802.1x在交换机的端口验证设置
    ASAv931安装&初始化及ASDM管理
    S5700与Cisco ACS做802.1x认证
    playwright
  • 原文地址:https://www.cnblogs.com/gongcb/p/2494502.html
Copyright © 2011-2022 走看看