Android 实现九宫格、点击图片放大全屏浏览等

项目GitHub地址https://github.com/tikeyc/TNinePlaceGridView_Android https://github.com/tikeyc/TikeycAndroid
玩Android不久,根据iOS实现思路https://github.com/tikeyc/TNinePlaceGridView
封装了一个。详情见TNinePlaceGridView

说说我的实现思路:

逐渐掌握了Android开发套路,是时候自己去封装一些东西了。网上看了一些例子,感觉不是我想要的那种,我希望是直接导入就用,没有Activity,没有xml布局文件,全代码创建那种,使用者用起来直接用到一个类或者两个类就OK的那种。故此花了一点时间封装了这么一个九宫格:
需要有这么一个控件,这个控件是一个图片控件TScallImageView,点击这个图片会从图片位置开始放大至全屏TImageListBgView,点击后全屏缩小到原来位置,且放大缩小过程背景透明可以看见当前UI界面;这个全屏大部分人可能是start一个Activity(这样的话还得再功能清单文件添加该Activity,这不是我想要的),这里我直接添加到了window上;这些代码逻辑主要都写在TImageListBgView类中。

这里需要获取图片相对于window的位置:这里自定义了一个记录位置信息的类TRect
package com.tikeyc.tikeycandroid.custom.TNinePlaceGridView;

/**
 * Created by public1 on 2017/5/23.
 */

public class TRect {

    private int left;
    private int top;
    private int width;
    private int height;

    public TRect(int left, int top, int width, int height) {
        this.left = left;
        this.top = top;
        this.width = width;
        this.height = height;
    }

    public int getLeft() {
        return left;
    }

    public int getTop() {
        return top;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public void setLeft(int left) {
        this.left = left;
    }

    public void setTop(int top) {
        this.top = top;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "TRect{" +
                "left=" + left +
                ", top=" + top +
                ", width=" + width +
                ", height=" + height +
                '}';
    }
}
图片控件:TScallImageView
  • 该控件可以xml中创建也可代码创建,不过在调用其showImageToWindow()方法之前,需设置一下几个属性值:其中imageId及imageIds可以是图片URL也可以是图片id值。
    public ViewGroup ninePlaceGridView;//外部设置
    public Object imageId;//外部设置
    public List<Object> imageIds;//外部设置
    public int currentIndex;//外部设置
package com.tikeyc.tnineplacegridviewlibrary.TNinePlaceGridView;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by public1 on 2017/5/19.
 */

public class TScallImageView extends android.support.v7.widget.AppCompatImageView {

    public static final int STATE_NORMAL = 0;
    public static final int STATE_TRANSFORM_IN = 1;
    public static final int STATE_TRANSFORM_OUT = 2;

    public ViewGroup ninePlaceGridView;//外部设置
    private TRect originalRect;//得到的第一个图片相对于window的位置
    private List<TRect> originalRects;//得到的第所有图片相对于window的位置
    public Object imageId;//外部设置
    public List<Object> imageIds;//外部设置
    public int currentIndex;//外部设置
    public TImageListBgView imageListBgView;

    public TScallImageView(Context context) {
        super(context);
        init();
    }

    public TScallImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public TScallImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                showImageToWindow();
            }
        });
    }


    /**获取每个图片相对于window的位置
     * @return
     */
    private List<TRect> getOriginalRects() {
        List<TRect> originalRects = new ArrayList<TRect>();
        int count = ninePlaceGridView.getChildCount();
        for (int i = 0; i < count; i++) {
            if (ninePlaceGridView.getChildAt(i) instanceof TScallImageView) {
                TScallImageView scallImageView = (TScallImageView) ninePlaceGridView.getChildAt(i);
                int[] outLocation = new int[2];
                scallImageView.getLocationInWindow(outLocation);
                Log.e("TAG","outLocation[0]:" + outLocation[0] + "outLocation[1]:" + outLocation[1]);
                TRect tRect = new TRect(outLocation[0],outLocation[1],scallImageView.getWidth(),scallImageView.getHeight());
                originalRects.add(tRect);
            } else {
                continue;
            }

        }
        this.originalRects = originalRects;
        return originalRects;
    }

    public void showImageToWindow() {
        int[] outLocation = new int[2];
        getLocationInWindow(outLocation);
//        originalRect = new TRect(getLeft(),getTop(),getWidth(),getHeight());
//        originalRect = new TRect(outLocation[0],outLocation[1] - TKCUtils.getStatusBarHeight(getContext()),getWidth(),getHeight());
        originalRect = new TRect(outLocation[0],outLocation[1],getWidth(),getHeight());
        imageListBgView = new TImageListBgView(getContext(),originalRect,this.imageId,this.imageIds,currentIndex);
        imageListBgView.imageId = imageId;
        imageListBgView.originalRects = getOriginalRects();
        imageListBgView.startTransform(TScallImageView.STATE_TRANSFORM_IN);

    }

}
TImageListBgView:图片放大缩小动画,横向滑动浏览等逻辑处理类
  • 点击手机的返回按键,缩小图片:这里需要注意一点,在window上添加视图后点击手机的返回按键,不会响应当前的Activity,因此需要在添加在window上的视图TImageListBgView内重写public boolean dispatchKeyEvent(KeyEvent event)方法来实现:
/**因此View添加在Window,点击手机返回按钮无法响应,
     * 重写此方法可以处理点击手机返回的逻辑处理,缩小图片到原位置
     * @param event
     * @return
     */
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {//2-4
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            if (mState == TScallImageView.STATE_TRANSFORM_IN) {
                startTransform(TScallImageView.STATE_TRANSFORM_OUT);
                return true;
            }
        }
        return super.dispatchKeyEvent(event);
    }
package com.tikeyc.tnineplacegridviewlibrary.TNinePlaceGridView;

import android.animation.Animator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.squareup.picasso.Picasso;

import java.util.List;

/**
 * Created by public1 on 2017/5/23.
 */

public class TImageListBgView extends RelativeLayout {

    public int mState = TScallImageView.STATE_NORMAL;
    private TRect originalRect;
    public List<TRect> originalRects;
    public Object imageId;
    public List<Object> imageIds;
    public int currentIndex;
    private ImageView animationIV;
    private LinearLayout gridViewBgView;
    private GridView gridView;
    private TPageHorizatalScrollView horizontalScrollView;
    private TPageControl pageControl;

    public TImageListBgView(Context context, TRect originalRect,Object imageId,List<Object> imageIds,int currentIndex) {
        super(context);
        this.originalRect = originalRect;
        this.imageId = imageId;
        this.imageIds = imageIds;
        this.currentIndex = currentIndex;
        setBackgroundColor(Color.TRANSPARENT);
        initSubViews();
    }

    public TImageListBgView(Context context) {
        super(context);
    }

    public TImageListBgView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TImageListBgView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**因此View添加在Window,点击手机返回按钮无法响应,
     * 重写此方法可以处理点击手机返回的逻辑处理,缩小图片到原位置
     * @param event
     * @return
     */
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {//2-4
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            if (mState == TScallImageView.STATE_TRANSFORM_IN) {
                startTransform(TScallImageView.STATE_TRANSFORM_OUT);
                return true;
            }
        }
        return super.dispatchKeyEvent(event);
    }

    @Override
    public boolean dispatchKeyEventPreIme(KeyEvent event) {//1-3
        return super.dispatchKeyEventPreIme(event);
    }


    private WindowManager windowManager;
    private void initSubViews() {
        //
        initImageListBgView();
        //
        initAnimationIV();
        //
        initHorizontalScrollView();
        //
        initGridView();
        //
        initPageControl();
    }

    private void initImageListBgView() {
        Activity activity = (Activity) getContext();
        windowManager = activity.getWindowManager();
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        layoutParams.width = TRect.getScreenWidth(getContext());
        layoutParams.height = TRect.getScreenHeight(getContext());
        //FLAG_LAYOUT_IN_SCREEN
        layoutParams.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN;
        layoutParams.format = PixelFormat.RGBA_8888;//让背景透明,放大过程可以看到当前界面
        layoutParams.verticalMargin = 0;
        windowManager.addView(this,layoutParams);
    }

    private void initAnimationIV() {
        animationIV = new ImageView(getContext());
//        imageView.setBackgroundColor(Color.RED);
        animationIV.setScaleType(ImageView.ScaleType.FIT_CENTER);
        LayoutParams params = new LayoutParams(originalRect.getWidth(),originalRect.getHeight());
        params.leftMargin = originalRect.getLeft();
        params.topMargin = originalRect.getTop();
        addView(animationIV,params);
//        Picasso.with(getContext()).load("http://ww2.sinaimg.cn/mw690/9e6995c9gw1f2uu70bzohj209q06g3yw.jpg").into(animationIV);
        if (imageId instanceof Integer) {
            animationIV.setImageResource((Integer) imageId);
        } else {
            Picasso.with(getContext()).load((String) imageId).into(animationIV);
        }

    }

    private void initHorizontalScrollView() {
        horizontalScrollView = new TPageHorizatalScrollView(getContext());
        LayoutParams hsLayoutParams = new LayoutParams(TRect.getScreenWidth(getContext()),TRect.getScreenHeight(getContext()));
        hsLayoutParams.leftMargin = 0;
        hsLayoutParams.topMargin = 0;
        addView(horizontalScrollView,hsLayoutParams);
        horizontalScrollView.mBaseScrollX = currentIndex*TRect.getScreenWidth(getContext());
        horizontalScrollView.setOnScrollToIndexListen(new TPageHorizatalScrollView.OnScrollToIndexListen() {
            @Override
            public void scrollToIndex(int index) {
                currentIndex = index;
                if (currentIndex >= imageIds.size()){
                    currentIndex = imageIds.size() - 1;
                } else if (currentIndex < 0) {
                    currentIndex = 0;
                }
                Log.e("TAG","currentIndex" + currentIndex);
                if (imageId instanceof Integer) {
                    animationIV.setImageResource((Integer) imageIds.get(currentIndex));
                } else {
                    Picasso.with(getContext()).load((String) imageIds.get(currentIndex)).into(animationIV);
                }

                originalRect = originalRects.get(currentIndex);
                pageControl.setCurrentPage(currentIndex);
            }
        });
        int numColumns = imageIds.size();
        gridViewBgView = new LinearLayout(getContext());
        LinearLayout.LayoutParams testParams = new LinearLayout.LayoutParams(TRect.getScreenWidth(getContext())*numColumns,TRect.getScreenHeight(getContext()));
        horizontalScrollView.addView(gridViewBgView,testParams);
    }


    private void initGridView() {
        int numColumns = imageIds.size();
        //
        gridView = new GridView(getContext());
        gridView.setNumColumns(numColumns);
        gridView.setColumnWidth(TRect.getScreenWidth(getContext()));
        LinearLayout.LayoutParams gridViewLayoutParams = new LinearLayout.LayoutParams(TRect.getScreenWidth(getContext())*numColumns,TRect.getScreenHeight(getContext()));
        gridViewLayoutParams.leftMargin = 0;
        gridViewLayoutParams.topMargin = 0;
        gridViewBgView.addView(gridView,gridViewLayoutParams);
        final TImageGridViewAdapter adapter = new TImageGridViewAdapter(getContext());
        adapter.imageIds = this.imageIds;
        gridView.setAdapter(adapter);
        adapter.setOnItemClickListener(new TImageGridViewAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int i, View view) {
                startTransform(TScallImageView.STATE_TRANSFORM_OUT);
            }
        });

//        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
//            @Override
//            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
//                startTransform(TScallImageView.STATE_TRANSFORM_OUT);
//            }
//        });
    }

    private void initPageControl() {
        pageControl = new TPageControl(getContext(),null);
        pageControl.setPageNumber(imageIds.size());
        pageControl.setSelectedColor(Color.RED);
        LayoutParams layoutParams = new LayoutParams(TRect.getScreenWidth(getContext()),40);
        layoutParams.topMargin = TRect.getScreenHeight(getContext()) - 100;
        addView(pageControl,layoutParams);
    }

    /**放大缩小动画
     * @param state
     */
    public void startTransform(final int state) {

        final int duration = 300;
        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setDuration(duration);
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        if (state == TScallImageView.STATE_TRANSFORM_IN) {
            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
            mState = TScallImageView.STATE_TRANSFORM_IN;
            gridViewBgView.setVisibility(INVISIBLE);
            pageControl.setVisibility(INVISIBLE);
//            PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat("scale", mTransfrom.startScale, mTransfrom.endScale);
            PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat("left",originalRect.getLeft(), 0);
            PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat("top", originalRect.getTop(), 0);
            PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat("width", originalRect.getWidth(), TRect.getScreenWidth(getContext()));
            PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat("height", originalRect.getHeight(), TRect.getScreenHeight(getContext()));
            PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("alpha", 0, 255);
            valueAnimator.setValues(leftHolder, topHolder, widthHolder, heightHolder, alphaHolder);
        } else {
//            setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
            gridViewBgView.setVisibility(INVISIBLE);
            pageControl.setVisibility(INVISIBLE);
            animationIV.setVisibility(VISIBLE);
            setBackgroundColor(Color.TRANSPARENT);
            mState = TScallImageView.STATE_TRANSFORM_OUT;
//            PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat("scale", mTransfrom.endScale, mTransfrom.startScale);
            PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat("left", animationIV.getLeft(), originalRect.getLeft());
            PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat("top", animationIV.getTop(), originalRect.getTop());
            PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat("width", animationIV.getWidth(), originalRect.getWidth());
            PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat("height", animationIV.getHeight(), originalRect.getHeight());
            PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("alpha", 255, 0);
            valueAnimator.setValues(leftHolder, topHolder, widthHolder, heightHolder, alphaHolder);

//            Handler handler = new Handler(){
//                @Override
//                public void handleMessage(Message msg) {
//                    super.handleMessage(msg);
//                    animationIV.setScaleType(ImageView.ScaleType.CENTER_CROP);//根据九宫格中的图片的显示模式设置
//                }
//            };
//            handler.sendEmptyMessageDelayed(0,duration*9/10);
        }

        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public synchronized void onAnimationUpdate(ValueAnimator animation) {
                //                mTransfrom.scale = (Float) animation.getAnimatedValue("scale");
                Float left = (Float) animation.getAnimatedValue("left");
                Float top = (Float) animation.getAnimatedValue("top");
                Float width = (Float) animation.getAnimatedValue("width");
                Float height = (Float) animation.getAnimatedValue("height");
                Integer mBgAlpha = (Integer) animation.getAnimatedValue("alpha");

                LayoutParams layoutParams = new LayoutParams(width.intValue(),height.intValue());
                layoutParams.leftMargin = left.intValue();
                layoutParams.topMargin = top.intValue();
                animationIV.setLayoutParams(layoutParams);
                setAlpha(mBgAlpha);
            }
        });
        final TImageListBgView[] imageListBgView = {this};
        valueAnimator.addListener(new ValueAnimator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                /*
                 * 如果是进入的话,当然是希望最后停留在center_crop的区域。但是如果是out的话,就不应该是center_crop的位置了
                 * , 而应该是最后变化的位置,因为当out的时候结束时,不回复视图是Normal,要不然会有一个突然闪动回去的bug
                 */
                // TODO 这个可以根据实际需求来修改
                if (mState == TScallImageView.STATE_TRANSFORM_IN) {
                    horizontalScrollView.baseSmoothScrollTo(0);
                    setBackgroundColor(Color.BLACK);
                    pageControl.setVisibility(VISIBLE);
                    Handler handler = new Handler(){
                        @Override
                        public void handleMessage(Message msg) {
                            super.handleMessage(msg);
                            gridViewBgView.setVisibility(VISIBLE);
                            animationIV.setVisibility(INVISIBLE);
                        }
                    };
                    handler.sendEmptyMessageDelayed(0, duration);
                } else if (mState == TScallImageView.STATE_TRANSFORM_OUT) {
                    gridViewBgView.removeView(gridView);
                    gridView = null;
                    horizontalScrollView.removeView(gridViewBgView);
                    gridViewBgView = null;
                    removeView(animationIV);
                    animationIV = null;
                    removeView(pageControl);
                    pageControl = null;
                    windowManager.removeView(imageListBgView[0]);
                    imageListBgView[0] = null;
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }
        });
        valueAnimator.start();


    }

}
如何使用,非常之简单
- List<List<Object>> imageNames2D = new ArrayList<List<Object>>();
  List<Object> imageNames = new ArrayList<Object>();
  imageNames2D.add(imageNames);
  imageNames.add(Object);
- TNinePlaceGridView ninePlaceGridView = (TNinePlaceGridView) view.findViewById(R.id.ninePlaceGridView);
- ninePlaceGridView.setImageNames(imageNames);

如下代码示例:

public class MainActivity extends AppCompatActivity {

    @ViewInject(R.id.listView)
    private ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        x.view().inject(this);
        init();

    }

    private void init() {

        List<List<Object>> imageNames2D = new ArrayList<List<Object>>();
        for (int i = 0; i < 30; i++) {
            ArrayList<Object> imageNames = new ArrayList<Object>();
            Random random = new Random();
            for (int j = 0; j <= random.nextInt(8); j++) {
                if (j%2 == 0) {
                    imageNames.add(R.mipmap.beauty);
//                    imageNames.add("http://7xi8d6.com1.z0.glb.clouddn.com/20171011084856_0YQ0jN_joanne_722_11_10_2017_8_39_5_505.jpeg");
                } else {
                    imageNames.add(R.mipmap.glenceluanch);
//                    imageNames.add("http://7xi8d6.com1.z0.glb.clouddn.com/2017-10-10-sakura.gun_10_10_2017_12_33_34_751.jpg");
                }
            }
            imageNames2D.add(imageNames);
        }
        ListViewAdapter listViewAdapter = new ListViewAdapter(this);
        listViewAdapter.imageNames2D = imageNames2D;
        listView.setAdapter(listViewAdapter);
    }


    @Override
    protected void onResume() {
        super.onResume();

    }

    @Override
    protected void onPause() {
        super.onPause();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

    }


    private class ListViewAdapter extends BaseAdapter {

        private Context context;
        public List<List<Object>> imageNames2D;

        public ListViewAdapter(Context context) {
            this.context = context;
        }

        @Override
        public int getCount() {
            if (imageNames2D != null) return imageNames2D.size();
            return 0;
        }

        @Override
        public Object getItem(int i) {
            return null;
        }

        @Override
        public long getItemId(int i) {
            return 0;
        }

        private class ViewHelper {
            CircleImageView imageViewIcon;
            TextView textViewNickName;
            TNinePlaceGridView ninePlaceGridView;

        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {

            ViewHelper viewHelper;
            if (view == null) {
                view = View.inflate(context,R.layout.timage_listactivity_listview_item,null);
                viewHelper = new ViewHelper();
                viewHelper.imageViewIcon = (CircleImageView) view.findViewById(R.id.imageViewIcon);
                viewHelper.textViewNickName = (TextView) view.findViewById(R.id.textViewNickName);
                viewHelper.ninePlaceGridView = (TNinePlaceGridView) view.findViewById(R.id.ninePlaceGridView);

                view.setTag(viewHelper);
            } else  {
                viewHelper = (ViewHelper) view.getTag();
            }
            List<Object> imageNames = this.imageNames2D.get(i);
            viewHelper.ninePlaceGridView.setImageNames(imageNames);

            return view;
        }
    }

}

 

posted @ 2018-04-24 13:38  星辰之力  阅读(1099)  评论(0编辑  收藏  举报