NineGridLayout九宫格图片使用



NineGridLayout

一个仿微信朋友圈和QQ空间的九宫格图片展示自定义控件。

GitHub:https://github.com/HMY314/NineGridLayout



一、介绍

    1、当只有1张图时,可以自己定制图片宽高,也可以使用默认九宫格的宽高;
    2、当只有4张图时,以2*2的方式显示;
    3、除以上两种情况下,都是按照3列方式显示,但这时有一些细节:
        a、如果只有9张图,当然是以3*3的方式显示;
        b、如果超过9张图,可以设置是否全部显示。
            如果设置不完全显示,则按照3*3的方式显示,但是在第9张图上会有一个带“+”号的数字,
            代表还有几张没有显示,这里是模仿了QQ空间图片超出9张的显示方式;
            如果设置全部显示,理所当然的将所有图片都显示出来。
    4、图片被按下时,会有一个变暗的效果,这也是模仿微信朋友圈的效果。

二、使用方法

1、核心类是NineGridLayout,继承自ViewGroup的抽象类,所以我们实际项目使用需要继承它,并要实现3个方法,如下:

  1. public abstract class NineGridLayout extends ViewGroup {  
  2.     //******************************其他代码省略**************************  
  3.   
  4.         /**  
  5.          * 显示一张图片  
  6.          * @param imageView  
  7.          * @param url  
  8.          * @param parentWidth 父控件宽度  
  9.          * @return true 代表按照九宫格默认大小显示,false 代表按照自定义宽高显示  
  10.          */  
  11.         protected abstract boolean displayOneImage(RatioImageView imageView, String url, int parentWidth);  
  12.   
  13.         protected abstract void displayImage(RatioImageView imageView, String url);  
  14.   
  15.         /** 
  16.          * 点击图片时执行 
  17.          */  
  18.         protected abstract void onClickImage(int position, String url, List<String> urlList);  
  19.     }  

2、我这里用NineGridTestLayout继承NineGridLayout实现,displayOneImage()与displayImage()中的参数都是显示图片需要的,我这里用的是ImageLoader显示图片,当然你也可以用其他的。

  1. public class NineGridTestLayout extends NineGridLayout {  
  2.   
  3.      protected static final int MAX_W_H_RATIO = 3;  
  4.   
  5.      public NineGridTestLayout(Context context) {  
  6.          super(context);  
  7.      }  
  8.   
  9.      public NineGridTestLayout(Context context, AttributeSet attrs) {  
  10.          super(context, attrs);  
  11.      }  
  12.   
  13.      @Override  
  14.      protected boolean displayOneImage(final RatioImageView imageView, String url, final int parentWidth) {  
  15.   
  16.         //这里是只显示一张图片的情况,显示图片的宽高可以根据实际图片大小自由定制,parentWidth 为该layout的宽度  
  17.          ImageLoader.getInstance().displayImage(imageView, url, ImageLoaderUtil.getPhotoImageOption(), new ImageLoadingListener() {  
  18.              @Override  
  19.              public void onLoadingStarted(String imageUri, View view) {  
  20.   
  21.              }  
  22.   
  23.              @Override  
  24.              public void onLoadingFailed(String imageUri, View view, FailReason failReason) {  
  25.   
  26.              }  
  27.   
  28.              @Override  
  29.              public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) {  
  30.                  int w = bitmap.getWidth();  
  31.                  int h = bitmap.getHeight();  
  32.   
  33.                  int newW;  
  34.                  int newH;  
  35.                  if (h > w * MAX_W_H_RATIO) {//h:w = 5:3  
  36.                      newW = parentWidth / 2;  
  37.                      newH = newW * 5 / 3;  
  38.                  } else if (h < w) {//h:w = 2:3  
  39.                      newW = parentWidth * 2 / 3;  
  40.                      newH = newW * 2 / 3;  
  41.                  } else {//newH:h = newW :w  
  42.                      newW = parentWidth / 2;  
  43.                      newH = h * newW / w;  
  44.                  }  
  45.                  setOneImageLayoutParams(imageView, newW, newH);  
  46.              }  
  47.   
  48.              @Override  
  49.              public void onLoadingCancelled(String imageUri, View view) {  
  50.   
  51.              }  
  52.          });  
  53.          return false;// true 代表按照九宫格默认大小显示(此时不要调用setOneImageLayoutParams);false 代表按照自定义宽高显示。  
  54.      }  
  55.   
  56.      @Override  
  57.      protected void displayImage(RatioImageView imageView, String url) {  
  58.          ImageLoaderUtil.getImageLoader(mContext).displayImage(url, imageView, ImageLoaderUtil.getPhotoImageOption());  
  59.      }  
  60.   
  61.      @Override  
  62.      protected void onClickImage(int i, String url, List<String> urlList) {  
  63.          Toast.makeText(mContext, "点击了图片" + url, Toast.LENGTH_SHORT).show();  
  64.      }  
  65. }  

3、在xml中实现

  1. <com.hmy.ninegridlayout.view.NineGridTestLayout xmlns:app="http://schemas.android.com/apk/res-auto"  
  2.     android:id="@+id/layout_nine_grid"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="wrap_content"  
  5.     android:layout_marginTop="8dp"  
  6.     app:sapcing="4dp" />  

app:sapcing是设置九宫格中图片之间的间隔。


4、使用:

  1. public List<String> urlList = new ArrayList<>();//图片url  
  2. NineGridTestLayout layout = (NineGridTestLayout) view.findViewById(R.id.layout_nine_grid);  
  3. layout.setIsShowAll(false); //当传入的图片数超过9张时,是否全部显示  
  4. layout.setSpacing(5); //动态设置图片之间的间隔  
  5. layout.setUrlList(urlList); //最后再设置图片url  

三、核心类

NineGridLayout.java

  1. /** 
  2.  * 描述: 
  3.  * 作者:HMY 
  4.  * 时间:2016/5/10 
  5.  */  
  6. public abstract class NineGridLayout extends ViewGroup {  
  7.   
  8.     private static final float DEFUALT_SPACING = 3f;  
  9.     private static final int MAX_COUNT = 9;  
  10.   
  11.     protected Context mContext;  
  12.     private float mSpacing = DEFUALT_SPACING;  
  13.     private int mColumns;  
  14.     private int mRows;  
  15.     private int mTotalWidth;  
  16.     private int mSingleWidth;  
  17.   
  18.     private boolean mIsShowAll = false;  
  19.     private boolean mIsFirst = true;  
  20.     private List<String> mUrlList = new ArrayList<>();  
  21.   
  22.     public NineGridLayout(Context context) {  
  23.         super(context);  
  24.         init(context);  
  25.     }  
  26.   
  27.     public NineGridLayout(Context context, AttributeSet attrs) {  
  28.         super(context, attrs);  
  29.         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NineGridLayout);  
  30.   
  31.         mSpacing = typedArray.getDimension(R.styleable.NineGridLayout_sapcing, DEFUALT_SPACING);  
  32.         typedArray.recycle();  
  33.         init(context);  
  34.     }  
  35.   
  36.     private void init(Context context) {  
  37.         mContext = context;  
  38.         if (getListSize(mUrlList) == 0) {  
  39.             setVisibility(GONE);  
  40.         }  
  41.     }  
  42.   
  43.     @Override  
  44.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  45.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  46.     }  
  47.   
  48.     @Override  
  49.     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  50.         mTotalWidth = right - left;  
  51.         mSingleWidth = (int) ((mTotalWidth - mSpacing * (3 - 1)) / 3);  
  52.         if (mIsFirst) {  
  53.             notifyDataSetChanged();  
  54.             mIsFirst = false;  
  55.         }  
  56.     }  
  57.   
  58.     /** 
  59.      * 设置间隔 
  60.      * 
  61.      * @param spacing 
  62.      */  
  63.     public void setSpacing(float spacing) {  
  64.         mSpacing = spacing;  
  65.     }  
  66.   
  67.     /** 
  68.      * 设置是否显示所有图片(超过最大数时) 
  69.      * 
  70.      * @param isShowAll 
  71.      */  
  72.     public void setIsShowAll(boolean isShowAll) {  
  73.         mIsShowAll = isShowAll;  
  74.     }  
  75.   
  76.     public void setUrlList(List<String> urlList) {  
  77.         if (getListSize(urlList) == 0) {  
  78.             setVisibility(GONE);  
  79.             return;  
  80.         }  
  81.         setVisibility(VISIBLE);  
  82.   
  83.         mUrlList.clear();  
  84.         mUrlList.addAll(urlList);  
  85.   
  86.         if (!mIsFirst) {  
  87.             notifyDataSetChanged();  
  88.         }  
  89.     }  
  90.   
  91.     public void notifyDataSetChanged() {  
  92.         removeAllViews();  
  93.         int size = getListSize(mUrlList);  
  94.         if (size > 0) {  
  95.             setVisibility(VISIBLE);  
  96.         } else {  
  97.             setVisibility(GONE);  
  98.         }  
  99.   
  100.         if (size == 1) {  
  101.             String url = mUrlList.get(0);  
  102.             RatioImageView imageView = createImageView(0, url);  
  103.   
  104.             //避免在ListView中一张图未加载成功时,布局高度受其他item影响  
  105.             LayoutParams params = getLayoutParams();  
  106.             params.height = mSingleWidth;  
  107.             setLayoutParams(params);  
  108.             imageView.layout(00, mSingleWidth, mSingleWidth);  
  109.   
  110.             boolean isShowDefualt = displayOneImage(imageView, url, mTotalWidth);  
  111.             if (isShowDefualt) {  
  112.                 layoutImageView(imageView, 0, url, false);  
  113.             } else {  
  114.                 addView(imageView);  
  115.             }  
  116.             return;  
  117.         }  
  118.   
  119.         generateChildrenLayout(size);  
  120.         layoutParams();  
  121.   
  122.         for (int i = 0; i < size; i++) {  
  123.             String url = mUrlList.get(i);  
  124.             RatioImageView imageView;  
  125.             if (!mIsShowAll) {  
  126.                 if (i < MAX_COUNT - 1) {  
  127.                     imageView = createImageView(i, url);  
  128.                     layoutImageView(imageView, i, url, false);  
  129.                 } else { //第9张时  
  130.                     if (size <= MAX_COUNT) {//刚好第9张  
  131.                         imageView = createImageView(i, url);  
  132.                         layoutImageView(imageView, i, url, false);  
  133.                     } else {//超过9张  
  134.                         imageView = createImageView(i, url);  
  135.                         layoutImageView(imageView, i, url, true);  
  136.                         break;  
  137.                     }  
  138.                 }  
  139.             } else {  
  140.                 imageView = createImageView(i, url);  
  141.                 layoutImageView(imageView, i, url, false);  
  142.             }  
  143.         }  
  144.     }  
  145.   
  146.     private void layoutParams() {  
  147.         int singleHeight = mSingleWidth;  
  148.   
  149.         //根据子view数量确定高度  
  150.         LayoutParams params = getLayoutParams();  
  151.         params.height = (int) (singleHeight * mRows + mSpacing * (mRows - 1));  
  152.         setLayoutParams(params);  
  153.     }  
  154.   
  155.     private RatioImageView createImageView(final int i, final String url) {  
  156.         RatioImageView imageView = new RatioImageView(mContext);  
  157.         imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);  
  158.         imageView.setOnClickListener(new OnClickListener() {  
  159.             @Override  
  160.             public void onClick(View v) {  
  161.                 onClickImage(i, url, mUrlList);  
  162.             }  
  163.         });  
  164.         return imageView;  
  165.     }  
  166.   
  167.     /** 
  168.      * @param imageView 
  169.      * @param url 
  170.      * @param showNumFlag 是否在最大值的图片上显示还有未显示的图片张数 
  171.      */  
  172.     private void layoutImageView(RatioImageView imageView, int i, String url, boolean showNumFlag) {  
  173.         final int singleWidth = (int) ((mTotalWidth - mSpacing * (3 - 1)) / 3);  
  174.         int singleHeight = singleWidth;  
  175.   
  176.         int[] position = findPosition(i);  
  177.         int left = (int) ((singleWidth + mSpacing) * position[1]);  
  178.         int top = (int) ((singleHeight + mSpacing) * position[0]);  
  179.         int right = left + singleWidth;  
  180.         int bottom = top + singleHeight;  
  181.   
  182.         imageView.layout(left, top, right, bottom);  
  183.   
  184.         addView(imageView);  
  185.         if (showNumFlag) {//添加超过最大显示数量的文本  
  186.             int overCount = getListSize(mUrlList) - MAX_COUNT;  
  187.             if (overCount > 0) {  
  188.                 float textSize = 30;  
  189.                 final TextView textView = new TextView(mContext);  
  190.                 textView.setText("+" + String.valueOf(overCount));  
  191.                 textView.setTextColor(Color.WHITE);  
  192.                 textView.setPadding(0, singleHeight / 2 - getFontHeight(textSize), 00);  
  193.                 textView.setTextSize(textSize);  
  194.                 textView.setGravity(Gravity.CENTER);  
  195.                 textView.setBackgroundColor(Color.BLACK);  
  196.                 textView.getBackground().setAlpha(120);  
  197.   
  198.                 textView.layout(left, top, right, bottom);  
  199.                 addView(textView);  
  200.             }  
  201.         }  
  202.         displayImage(imageView, url);  
  203.     }  
  204.   
  205.     private int[] findPosition(int childNum) {  
  206.         int[] position = new int[2];  
  207.         for (int i = 0; i < mRows; i++) {  
  208.             for (int j = 0; j < mColumns; j++) {  
  209.                 if ((i * mColumns + j) == childNum) {  
  210.                     position[0] = i;//行  
  211.                     position[1] = j;//列  
  212.                     break;  
  213.                 }  
  214.             }  
  215.         }  
  216.         return position;  
  217.     }  
  218.   
  219.     /** 
  220.      * 根据图片个数确定行列数量 
  221.      * 
  222.      * @param length 
  223.      */  
  224.     private void generateChildrenLayout(int length) {  
  225.         if (length <= 3) {  
  226.             mRows = 1;  
  227.             mColumns = length;  
  228.         } else if (length <= 6) {  
  229.             mRows = 2;  
  230.             mColumns = 3;  
  231.             if (length == 4) {  
  232.                 mColumns = 2;  
  233.             }  
  234.         } else {  
  235.             mColumns = 3;  
  236.             if (mIsShowAll) {  
  237.                 mRows = length / 3;  
  238.                 int b = length % 3;  
  239.                 if (b > 0) {  
  240.                     mRows++;  
  241.                 }  
  242.             } else {  
  243.                 mRows = 3;  
  244.             }  
  245.         }  
  246.   
  247.     }  
  248.   
  249.     protected void setOneImageLayoutParams(RatioImageView imageView, int width, int height) {  
  250.         imageView.setLayoutParams(new LayoutParams(width, height));  
  251.         imageView.layout(00, width, height);  
  252.   
  253.         LayoutParams params = getLayoutParams();  
  254. //        params.width = width;  
  255.         params.height = height;  
  256.         setLayoutParams(params);  
  257.     }  
  258.   
  259.     private int getListSize(List<String> list) {  
  260.         if (list == null || list.size() == 0) {  
  261.             return 0;  
  262.         }  
  263.         return list.size();  
  264.     }  
  265.   
  266.     private int getFontHeight(float fontSize) {  
  267.         Paint paint = new Paint();  
  268.         paint.setTextSize(fontSize);  
  269.         Paint.FontMetrics fm = paint.getFontMetrics();  
  270.         return (int) Math.ceil(fm.descent - fm.ascent);  
  271.     }  
  272.   
  273.     /** 
  274.      * @param imageView 
  275.      * @param url 
  276.      * @param parentWidth 父控件宽度 
  277.      * @return true 代表按照九宫格默认大小显示,false 代表按照自定义宽高显示 
  278.      */  
  279.     protected abstract boolean displayOneImage(RatioImageView imageView, String url, int parentWidth);  
  280.   
  281.     protected abstract void displayImage(RatioImageView imageView, String url);  
  282.   
  283.     protected abstract void onClickImage(int position, String url, List<String> urlList);  
  284. }  

RatioImageView.Java

该类有两个功能:

1、是用于ImageView被按下时有变暗效果

2、ImageView的宽高根据设置的比例动态适配高度,如在xml中设置 app:ratio="2" ,ImageView的高度根据其宽度改变,但始终是宽的2倍,该功能在该项目中没有使用。

  1. /** 
  2.  * 根据宽高比例自动计算高度ImageView 
  3.  * Created by HMY on 2016/4/21. 
  4.  */  
  5. public class RatioImageView extends ImageView {  
  6.   
  7.     /** 
  8.      * 宽高比例 
  9.      */  
  10.     private float mRatio = 0f;  
  11.   
  12.     public RatioImageView(Context context, AttributeSet attrs, int defStyleAttr) {  
  13.         super(context, attrs, defStyleAttr);  
  14.     }  
  15.   
  16.     public RatioImageView(Context context, AttributeSet attrs) {  
  17.         super(context, attrs);  
  18.         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RatioImageView);  
  19.   
  20.         mRatio = typedArray.getFloat(R.styleable.RatioImageView_ratio, 0f);  
  21.         typedArray.recycle();  
  22.     }  
  23.   
  24.     public RatioImageView(Context context) {  
  25.         super(context);  
  26.     }  
  27.   
  28.     /** 
  29.      * 设置ImageView的宽高比 
  30.      * 
  31.      * @param ratio 
  32.      */  
  33.     public void setRatio(float ratio) {  
  34.         mRatio = ratio;  
  35.     }  
  36.   
  37.     @Override  
  38.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  39.         int width = MeasureSpec.getSize(widthMeasureSpec);  
  40.         if (mRatio != 0) {  
  41.             float height = width / mRatio;  
  42.             heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) height, MeasureSpec.EXACTLY);  
  43.         }  
  44.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  45.     }  
  46.   
  47.     @Override  
  48.     public boolean onTouchEvent(MotionEvent event) {  
  49.   
  50.         switch (event.getAction()) {  
  51.             case MotionEvent.ACTION_DOWN:  
  52.                 Drawable drawable = getDrawable();  
  53.                 if (drawable != null) {  
  54.                     drawable.mutate().setColorFilter(Color.GRAY,  
  55.                             PorterDuff.Mode.MULTIPLY);  
  56.                 }  
  57.                 break;  
  58.             case MotionEvent.ACTION_MOVE:  
  59.                 break;  
  60.             case MotionEvent.ACTION_CANCEL:  
  61.             case MotionEvent.ACTION_UP:  
  62.                 Drawable drawableUp = getDrawable();  
  63.                 if (drawableUp != null) {  
  64.                     drawableUp.mutate().clearColorFilter();  
  65.                 }  
  66.                 break;  
  67.         }  
  68.   
  69.         return super.onTouchEvent(event);  
  70.     }  
  71.   
  72. }  


代码可在我的GitHub上下载,地址:https://github.com/HMY314/NineGridLayout


效果图

    


转载来源:http://blog.csdn.net/hmyang314/article/details/51415396



猜你喜欢

转载自blog.csdn.net/wang__wyj/article/details/74733550