yanyi 4 лет назад
Родитель
Сommit
1e35ed2ef8
25 измененных файлов с 906 добавлено и 23 удалено
  1. 82 0
      README.md
  2. 3 5
      app/build.gradle
  3. 30 2
      build.gradle
  4. 2 3
      gradle/wrapper/gradle-wrapper.properties
  5. 28 0
      image_grid_lib/bintrayUpload.gradle
  6. 9 5
      image_grid_lib/build.gradle
  7. 7 0
      image_grid_lib/src/main/AndroidManifest.xml
  8. 45 0
      image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/GlideUtils.java
  9. 14 0
      image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageBean.java
  10. 55 0
      image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageDetailsActivity.java
  11. 35 0
      image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageDetailsAdapter.java
  12. 47 0
      image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageDetailsFragment.java
  13. 116 0
      image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageRecycler.java
  14. 301 0
      image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImagerAdapter.java
  15. 46 0
      image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/SquareRelativeLayout.java
  16. 7 0
      image_grid_lib/src/main/res/layout/benyanyi_frg_img.xml
  17. 23 0
      image_grid_lib/src/main/res/layout/benyanyi_img_details.xml
  18. 20 0
      image_grid_lib/src/main/res/layout/benyanyi_item_img.xml
  19. BIN
      image_grid_lib/src/main/res/mipmap-xxhdpi/add_photo.png
  20. BIN
      image_grid_lib/src/main/res/mipmap-xxhdpi/back_white.png
  21. BIN
      image_grid_lib/src/main/res/mipmap-xxhdpi/delete_photo.png
  22. BIN
      image_grid_lib/src/main/res/mipmap-xxhdpi/image_default.png
  23. 31 0
      image_grid_lib/src/main/res/values/attrs.xml
  24. 5 0
      image_grid_lib/src/main/res/values/dimen.xml
  25. 0 8
      settings.gradle

+ 82 - 0
README.md

@@ -0,0 +1,82 @@
+# BaseSQLite
+
+![](https://img.shields.io/badge/ImageGrid-1.0.1-green)
+
+介绍
+---
+##### 旨在将sqlite使用变得简单化,处理数据时链式调用
+
+使用
+---
+### 根目录下build.gradle添加Maven地址
+~~~
+repositories {
+        maven {
+            url "http://maven.keleyanyi.com/repository/benyanyi/"
+        }
+    }
+~~~
+### module 下添加
+~~~
+implementation 'com.yanyi.benyanyi:ImageGrid:1.0.1'
+~~~
+
+或者
+~~~
+<dependency>
+  <groupId>com.yanyi.benyanyi</groupId>
+  <artifactId>ImageGrid</artifactId>
+  <version>1.0.1</version>
+  <type>aar</type>
+</dependency>
+~~~
+
+### 使用介绍
+
+#### xml配置说明
+* android:maxLength 列表最大长度
+* ir_is_add 是否需要添加图片操作
+*ir_add_res 添加图片图标*
+ <!--列表最大长度-->
+        <attr name="android:maxLength" />
+        <!--是否需要添加图片操作-->
+        <attr name="ir_is_add" format="boolean" />
+        <!--添加图片图标-->
+        <attr name="ir_add_res" format="reference" />
+        <!--默认图片-->
+        <attr name="ir_default_res" format="reference" />
+        <!--最小显示个数-->
+        <attr name="ir_min_show_size" format="integer" />
+        <!--是否需要删除图片-->
+        <attr name="ir_show_delete" format="boolean" />
+        <!--删除图标-->
+        <attr name="ir_delete_res" format="reference" />
+        <!--删除图标内边距-->
+        <attr name="ir_delete_padding" format="dimension" />
+        <!--删除图标位置-->
+        <attr name="ir_delete_gravity" format="enum">
+            <enum name="right" value="0" />
+            <enum name="left" value="1" />
+            <enum name="center" value="2" />
+            <enum name="top" value="3" />
+            <enum name="bottom" value="4" />
+        </attr>
+
+更新记录
+----
+* 2021-10-01 提交1.0.1版本,第一次更新
+
+<!--#### 下一版本预计添加内容-->
+<!--优化条件方法,将条件方法全部归入一个方法中-->
+
+<!--## 联系-->
+<!--若在使用过程中出现什么问题,可以联系作者<br/>-->
+<!--作者:演绎<br/>-->
+<!--QQ:1541612424<br/>-->
+<!--email: work@yanyi.red<br/>-->
+<!--微信公众号:benyanyi(演绎未来)&nbsp;&nbsp;&nbsp;将会不定期的更新关于android的一些文章-->
+
+<!--生成javadoc 防止混淆 加入  -encoding utf-8 -charset utf-8-->
+    
+
+        

+ 3 - 5
app/build.gradle

@@ -1,7 +1,4 @@
-plugins {
-    id 'com.android.application'
-}
-
+apply plugin: 'com.android.application'
 android {
     compileSdk 31
 
@@ -32,7 +29,8 @@ dependencies {
     implementation 'androidx.appcompat:appcompat:1.2.0'
     implementation 'com.google.android.material:material:1.3.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
-    testImplementation 'junit:junit:4.+'
+    testImplementation 'junit:junit:4.13.2'
     androidTestImplementation 'androidx.test.ext:junit:1.1.2'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+    implementation project(path: ':image_grid_lib')
 }

+ 30 - 2
build.gradle

@@ -3,15 +3,43 @@ buildscript {
     repositories {
         google()
         mavenCentral()
+        maven { url 'http://maven.keleyanyi.com/repository/benyanyi/' }
+        maven {
+            allowInsecureProtocol true
+            url 'http://www.idescout.com/maven/repo/'
+            name 'IDEScout, Inc.'
+        }
     }
     dependencies {
-        classpath "com.android.tools.build:gradle:7.0.2"
+        classpath 'com.android.tools.build:gradle:4.1.3'
+        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
     }
 }
+allprojects {
+    repositories {
+        google()
+        jcenter()
+        maven { url 'http://maven.keleyanyi.com/repository/benyanyi/' }
+        maven {
+            url 'http://www.idescout.com/maven/repo/'
+            name 'IDEScout, Inc.'
+        }
+        //解决中文乱码问题
+        tasks.withType(Javadoc) { //兼容中文
+            options.addStringOption('Xdoclint:none', '-quiet')
+            options.addStringOption('encoding', 'UTF-8')
+            options {
+                encoding "UTF-8"
+                charSet 'UTF-8'
+                links "http://docs.oracle.com/javase/7/docs/api"
+            }
+        }
+    }
+}
 
 task clean(type: Delete) {
     delete rootProject.buildDir
-}
+}

+ 2 - 3
gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,5 @@
-#Mon Sep 20 23:26:51 CST 2021
 distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
 distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
 zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists

+ 28 - 0
image_grid_lib/bintrayUpload.gradle

@@ -0,0 +1,28 @@
+apply plugin: 'maven-publish'
+apply plugin: 'maven'
+
+Properties properties = new Properties()
+properties.load(project.rootProject.file('local.properties').newDataInputStream())
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: properties.getProperty("POM_URL")) {
+                authentication(userName: properties.getProperty("nexus.user"), password: properties.getProperty("nexus.password"))
+            }
+
+            pom.groupId = properties.getProperty("POM_GROUP_ID")
+            pom.artifactId = properties.getProperty("POM_ATRIFACT_ID")
+            pom.version = properties.getProperty("POM_VERSION")
+
+            pom.project {
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                    }
+                }
+            }
+        }
+    }
+}
+//gradlew uploadArchives    terminal中输入

+ 9 - 5
image_grid_lib/build.gradle

@@ -1,6 +1,5 @@
-plugins {
-    id 'com.android.library'
-}
+apply plugin: 'com.android.library'
+
 
 android {
     compileSdk 31
@@ -31,7 +30,12 @@ dependencies {
 
     implementation 'androidx.appcompat:appcompat:1.2.0'
     implementation 'com.google.android.material:material:1.3.0'
-    testImplementation 'junit:junit:4.+'
+    implementation 'androidx.recyclerview:recyclerview:1.2.1'
+    testImplementation 'junit:junit:4.13.2'
     androidTestImplementation 'androidx.test.ext:junit:1.1.2'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
-}
+
+    implementation 'com.github.bumptech.glide:glide:4.12.0'
+    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
+}
+apply from: 'bintrayUpload.gradle'

+ 7 - 0
image_grid_lib/src/main/AndroidManifest.xml

@@ -2,4 +2,11 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.benyanyi.image_grid_lib">
 
+    <application>
+        <activity
+            android:name=".ImageDetailsActivity"
+            android:launchMode="singleTask"
+            android:screenOrientation="portrait"
+            android:windowSoftInputMode="adjustPan|stateHidden" />
+    </application>
 </manifest>

+ 45 - 0
image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/GlideUtils.java

@@ -0,0 +1,45 @@
+package com.benyanyi.image_grid_lib;
+
+import android.text.TextUtils;
+import android.widget.ImageView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.RequestManager;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+
+/**
+ * @author mylove
+ * @date 2021/9/29
+ * @email ben@yanyi.red
+ * @overview
+ */
+class GlideUtils {
+    static void loadImg(ImageView imageView, String imgUrl, int mDefaultRes) {
+        boolean isGif = false;
+        if (imgUrl == null || TextUtils.isEmpty(imgUrl)) {
+            isGif = false;
+        } else {
+            int lastIndexOf = imgUrl.lastIndexOf(".gif");
+            isGif = lastIndexOf == (imgUrl.length() - 4);
+        }
+        RequestManager requestManager = Glide.with(imageView.getContext());
+        if (isGif) {
+            requestManager.asGif().load(imgUrl)
+                    .placeholder(mDefaultRes)
+                    .fallback(mDefaultRes)
+                    .error(mDefaultRes)
+                    .dontAnimate()
+                    .diskCacheStrategy(DiskCacheStrategy.ALL)
+                    .into(imageView);
+        } else {
+            requestManager.load(imgUrl)
+                    .placeholder(mDefaultRes)
+                    .fallback(mDefaultRes)
+                    .error(mDefaultRes)
+                    .dontAnimate()
+                    .diskCacheStrategy(DiskCacheStrategy.ALL)
+                    .into(imageView);
+        }
+
+    }
+}

+ 14 - 0
image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageBean.java

@@ -0,0 +1,14 @@
+package com.benyanyi.image_grid_lib;
+
+/**
+ * @author mylove
+ * @date 2021/9/28
+ * @email ben@yanyi.red
+ * @overview
+ */
+class ImageBean {
+
+    private String url;
+    private boolean isAdd;
+
+}

+ 55 - 0
image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageDetailsActivity.java

@@ -0,0 +1,55 @@
+package com.benyanyi.image_grid_lib;
+
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import androidx.viewpager2.widget.ViewPager2;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author mylove
+ * @date 2021/9/30
+ * @email ben@yanyi.red
+ * @overview
+ */
+public class ImageDetailsActivity extends AppCompatActivity {
+
+    private ViewPager2 viewPager;
+
+    private int mDefaultRes = R.mipmap.image_default;//默认图片
+    private int position = 0;
+
+    private List<String> imgUrls = new ArrayList<>();
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.benyanyi_img_details);
+        viewPager = findViewById(R.id.view_pager);
+        findViewById(R.id.back).setOnClickListener(view -> finish());
+        Bundle bundle = getIntent().getExtras();
+        String urls = bundle.getString("urls", "");
+        String indexUrl = bundle.getString("indexUrl", "");
+        mDefaultRes = bundle.getInt("mDefaultRes", mDefaultRes);
+        if (urls.isEmpty() && TextUtils.isEmpty(urls)) {
+            String[] split = urls.split(",");
+            imgUrls.addAll(Arrays.asList(split));
+        }
+        List<Fragment> fragments = new ArrayList<>();
+        for (int i = 0; i < imgUrls.size(); i++) {
+            fragments.add(ImageDetailsFragment.newInstance(indexUrl, mDefaultRes));
+            if (indexUrl.equals(imgUrls.get(i))) {
+                position = i;
+            }
+        }
+        ImageDetailsAdapter adapter = new ImageDetailsAdapter(this, fragments);
+        viewPager.setAdapter(adapter);
+        viewPager.setCurrentItem(position);
+    }
+}

+ 35 - 0
image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageDetailsAdapter.java

@@ -0,0 +1,35 @@
+package com.benyanyi.image_grid_lib;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+
+import java.util.List;
+
+/**
+ * @author mylove
+ * @date 2021/9/30
+ * @email ben@yanyi.red
+ * @overview
+ */
+class ImageDetailsAdapter extends FragmentStateAdapter {
+
+    private List<Fragment> fragments;
+
+    public ImageDetailsAdapter(@NonNull FragmentActivity fragmentActivity, List<Fragment> fragments) {
+        super(fragmentActivity);
+        this.fragments = fragments;
+    }
+
+    @NonNull
+    @Override
+    public Fragment createFragment(int position) {
+        return fragments.get(position);
+    }
+
+    @Override
+    public int getItemCount() {
+        return fragments.size();
+    }
+}

+ 47 - 0
image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageDetailsFragment.java

@@ -0,0 +1,47 @@
+package com.benyanyi.image_grid_lib;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+/**
+ * @author mylove
+ * @date 2021/9/30
+ * @email ben@yanyi.red
+ * @overview
+ */
+class ImageDetailsFragment extends Fragment {
+
+    private ImageView imageView;
+
+    private String imgUrl;
+    private int mDefaultRes = R.mipmap.image_default;//默认图片
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.benyanyi_frg_img, container, false);
+        imageView = view.findViewById(R.id.img);
+        if (getArguments() != null) {
+            imgUrl = getArguments().getString("imgUrl", "");
+            mDefaultRes = getArguments().getInt("mDefaultRes", mDefaultRes);
+        }
+        GlideUtils.loadImg(imageView, imgUrl, mDefaultRes);
+        return view;
+    }
+
+    public static ImageDetailsFragment newInstance(String url, int mDefaultRes) {
+        Bundle args = new Bundle();
+        args.putString("imgUrl", url);
+        args.putInt("mDefaultRes", mDefaultRes);
+        ImageDetailsFragment fragment = new ImageDetailsFragment();
+        fragment.setArguments(args);
+        return fragment;
+    }
+}

+ 116 - 0
image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImageRecycler.java

@@ -0,0 +1,116 @@
+package com.benyanyi.image_grid_lib;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.Collection;
+
+/**
+ * @author mylove
+ * @date 2021/9/22
+ * @email ben@yanyi.red
+ * @overview
+ */
+public class ImageRecycler extends RecyclerView {
+
+    private int mMaxLength = 0;//列表最大长度
+    private boolean isAdd = false;//是否需要添加图片操作
+    private int mAddRes = R.mipmap.add_photo; //添加图片图标
+    private int mDefaultRes = R.mipmap.image_default;//默认图片
+    private int mMinShowSize = 0;//最小显示个数
+    private boolean mShowDelete = false;//是否需要删除图片
+    private int mDeleteRes = R.mipmap.delete_photo;//删除图标
+    private int mDeletePadding = 0;//删除图标内边距
+    private int mGravity = 0;//默认位于右边
+    private ImagerAdapter mAdapter;
+
+
+    public ImageRecycler(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init(context, attrs);
+    }
+
+    public ImageRecycler(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context, attrs);
+    }
+
+    private void init(Context context, AttributeSet attrs) {
+        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ImageRecycler);
+        this.mMaxLength = ta.getInt(R.styleable.ImageRecycler_android_maxLength, 0);
+        this.isAdd = ta.getBoolean(R.styleable.ImageRecycler_ir_is_add, false);
+        this.mAddRes = ta.getResourceId(R.styleable.ImageRecycler_ir_add_res, R.mipmap.add_photo);
+        this.mDefaultRes = ta.getResourceId(R.styleable.ImageRecycler_ir_default_res, R.mipmap.image_default);
+        this.mMinShowSize = ta.getInt(R.styleable.ImageRecycler_ir_min_show_size, 0);
+        this.mShowDelete = ta.getBoolean(R.styleable.ImageRecycler_ir_show_delete, false);
+        this.mDeleteRes = ta.getInt(R.styleable.ImageRecycler_ir_delete_res, R.mipmap.delete_photo);
+        this.mDeletePadding = ta.getDimensionPixelSize(R.styleable.ImageRecycler_ir_delete_padding, getResources().getDimensionPixelSize(R.dimen.dp5));
+        this.mGravity = ta.getInt(R.styleable.ImageRecycler_ir_delete_gravity, 0);
+        this.mAdapter = new ImagerAdapter(mMaxLength, isAdd, mAddRes, mDefaultRes, mMinShowSize, mShowDelete, mDeleteRes, mDeletePadding, mGravity);
+        ta.recycle();
+    }
+
+    public void setOnAddImgClick(OnAddImgClick onAddImgClick) {
+        this.mAdapter.setOnAddImgClick(onAddImgClick);
+    }
+
+    @Override
+    public void setLayoutManager(@Nullable LayoutManager layout) {
+        if (layout instanceof GridLayoutManager) {
+            super.setLayoutManager(layout);
+        } else {
+            super.setLayoutManager(new GridLayoutManager(this.getContext(), 3));
+        }
+    }
+
+    public void setAdapter(@Nullable Adapter adapter) {
+        super.setAdapter(this.mAdapter);
+    }
+
+    public void setAdapter() {
+        super.setAdapter(this.mAdapter);
+    }
+
+    public void addData(@IntRange(from = 0L) int position, @NonNull String imgUrl) {
+        this.mAdapter.addData(position, imgUrl);
+    }
+
+    public void addData(@NonNull String imgUrl) {
+        this.mAdapter.addData(imgUrl);
+    }
+
+    public void remove(@IntRange(from = 0L) int position) {
+        this.mAdapter.remove(position);
+    }
+
+    public void setData(@IntRange(from = 0L) int index, @NonNull String imgUrl) {
+        this.mAdapter.setData(index, imgUrl);
+    }
+
+    public void addData(@IntRange(from = 0L) int position, @NonNull Collection<? extends String> imgUrls) {
+        this.mAdapter.addData(position, imgUrls);
+    }
+
+    public void addData(@NonNull Collection<? extends String> imgUrls) {
+        this.mAdapter.addData(imgUrls);
+    }
+
+    public void replaceData(@NonNull Collection<? extends String> imgUrls) {
+        this.mAdapter.replaceData(imgUrls);
+    }
+
+    public ImagerAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    public interface OnAddImgClick {
+        void onAddImgClick();
+    }
+}

+ 301 - 0
image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/ImagerAdapter.java

@@ -0,0 +1,301 @@
+package com.benyanyi.image_grid_lib;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author mylove
+ * @date 2021/9/27
+ * @email ben@yanyi.red
+ * @overview
+ */
+public class ImagerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+
+    private List<String> mData = new ArrayList<>();
+    private int mMaxLength = 0;//列表最大长度
+    private boolean isAdd = false;//是否需要添加图片操作
+    private int mAddRes = R.mipmap.add_photo; //添加图片图标
+    private int mDefaultRes = R.mipmap.image_default;//默认图片
+    private int mMinShowSize = 0;//最小显示个数
+    private boolean mShowDelete = false;//是否需要删除图片
+    private int mDeleteRes = R.mipmap.delete_photo;//删除图标
+    private int mDeletePadding = 0;//删除图标内边距
+    private int mGravity = 0;//默认位于右边
+
+    private final int NONE_VIEW = 0;
+    private final int FOOTER_TYPE = 1;
+
+    private ImageRecycler.OnAddImgClick onAddImgClick;
+
+    public ImagerAdapter(int mMaxLength, boolean isAdd, int mAddRes, int mDefaultRes, int mMinShowSize, boolean mShowDelete, int mDeleteRes, int mDeletePadding, int mGravity) {
+        this.mMaxLength = mMaxLength;
+        this.isAdd = isAdd;
+        this.mAddRes = mAddRes;
+        this.mDefaultRes = mDefaultRes;
+        this.mMinShowSize = mMinShowSize;
+        this.mShowDelete = mShowDelete;
+        this.mDeleteRes = mDeleteRes;
+        this.mDeletePadding = mDeletePadding;
+        this.mGravity = mGravity;
+    }
+
+    @NonNull
+    @Override
+    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.benyanyi_item_img, parent, false);
+        if (viewType == FOOTER_TYPE) {
+            return new FooterViewHolder(view);
+        } else {
+            return new ViewHolder(view);
+        }
+    }
+
+    // <enum name="right" value="0" />
+//            <enum name="left" value="1" />
+//            <enum name="center" value="2" />
+//            <enum name="top" value="3" />
+//            <enum name="bottom" value="4" />
+    @Override
+    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+        if (holder instanceof ViewHolder) {
+//            if (mShowDelete) {
+//                ((ViewHolder) holder).deleteImg.setVisibility(View.VISIBLE);
+//                ((ViewHolder) holder).deleteImg.setImageResource(mDeleteRes);
+//                ((ViewHolder) holder).deleteImg.setPadding(mDeletePadding, mDeletePadding, mDeletePadding, mDeletePadding);
+////                ((ViewHolder) holder).itemRelative
+//            } else {
+//                ((ViewHolder) holder).deleteImg.setVisibility(View.GONE);
+//            }
+            if (mShowDelete) {
+                ImageView imageView = new ImageView(holder.itemView.getContext());
+                imageView.setImageResource(mDeleteRes);
+                imageView.setPadding(mDeletePadding, mDeletePadding, mDeletePadding, mDeletePadding);
+                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
+                switch (mGravity) {
+                    case 1:
+                        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
+                    case 2:
+                        layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+                        break;
+                    case 3:
+                        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
+                        break;
+                    case 4:
+                        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
+                        break;
+                    default:
+                        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
+                        break;
+                }
+                ((ViewHolder) holder).itemRelative.addView(imageView, layoutParams);
+                imageView.setOnClickListener(view -> remove(position));
+            }
+            GlideUtils.loadImg(((ViewHolder) holder).img, mData.get(position), mDefaultRes);
+            ((ViewHolder) holder).img.setOnClickListener(view -> {
+                StringBuilder urls = new StringBuilder();
+                for (int i = 0; i < mData.size(); i++) {
+                    urls.append(mData.get(i)).append(",");
+                }
+                if (urls.length() > 0 && urls.length() > 1) {
+                    urls.deleteCharAt(urls.length() - 1);
+                } else {
+                    urls = new StringBuilder();
+                }
+                Intent intent = new Intent(holder.itemView.getContext(), ImageDetailsActivity.class);
+                Bundle bundle = new Bundle();
+                bundle.putString("urls", urls.toString());
+                bundle.putString("indexUrl", mData.get(position));
+                bundle.putInt("mDefaultRes", mDefaultRes);
+                holder.itemView.getContext().startActivity(intent, bundle);
+            });
+        } else if (holder instanceof FooterViewHolder) {
+            if (mAddRes > 0) {
+                ((FooterViewHolder) holder).img.setImageResource(mAddRes);
+            }
+            ((FooterViewHolder) holder).itemRelative.setOnClickListener(view -> {
+                if (onAddImgClick != null) {
+                    onAddImgClick.onAddImgClick();
+                }
+            });
+        }
+    }
+
+    public void setOnAddImgClick(ImageRecycler.OnAddImgClick onAddImgClick) {
+        this.onAddImgClick = onAddImgClick;
+    }
+
+    @Override
+    public int getItemCount() {
+        int size = 0;
+        if (isAdd) {
+            if (mMinShowSize > 0) {
+                size = mMinShowSize;
+            } else {
+                size += 1;
+            }
+        }
+        if (mMaxLength <= 0 || mData.size() <= mMaxLength) {
+            size += mData.size();
+        } else {
+            size += mMaxLength;
+        }
+        return size;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (isFooter(position)) {
+            return FOOTER_TYPE;
+        } else {
+            return NONE_VIEW;
+        }
+    }
+
+    private boolean isFooter(int position) {
+        if (isAdd) {
+            if (mMinShowSize > 0) {
+                return position < getItemCount() && position >= getItemCount() - mMinShowSize;
+            } else {
+                return position < getItemCount() && position >= getItemCount() - 1;
+            }
+        } else {
+            return false;
+        }
+
+    }
+
+    /**
+     * 将Header、Footer挂靠到RecyclerView
+     *
+     * @param recyclerView
+     */
+    @Override
+    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
+        super.onAttachedToRecyclerView(recyclerView);
+        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
+        if (manager instanceof GridLayoutManager) {   // 布局是GridLayoutManager所管理
+            final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager;
+            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
+                @Override
+                public int getSpanSize(int position) {
+                    // 如果是Header、Footer的对象则占据spanCount的位置,否则就只占用1个位置
+                    return (isFooter(position)) ? gridLayoutManager.getSpanCount() : 1;
+                }
+            });
+        }
+    }
+
+    public void addData(@IntRange(from = 0L) int position, @NonNull String data) {
+        this.mData.add(position, data);
+        this.notifyItemInserted(position);
+        this.compatibilityDataSizeChanged(1);
+    }
+
+    public void addData(@NonNull String data) {
+        this.mData.add(data);
+        this.notifyItemInserted(this.mData.size());
+        this.compatibilityDataSizeChanged(1);
+    }
+
+    public void remove(@IntRange(from = 0L) int position) {
+        this.mData.remove(position);
+        this.notifyItemRemoved(position);
+        this.compatibilityDataSizeChanged(0);
+        this.notifyItemRangeChanged(position, this.mData.size() - position);
+    }
+
+    public void setData(@IntRange(from = 0L) int index, @NonNull String data) {
+        this.mData.set(index, data);
+        this.notifyItemChanged(index);
+    }
+
+    public void addData(@IntRange(from = 0L) int position, @NonNull Collection<? extends String> newData) {
+        this.mData.addAll(position, newData);
+        this.notifyItemRangeInserted(position, newData.size());
+        this.compatibilityDataSizeChanged(newData.size());
+    }
+
+    public void addData(@NonNull Collection<? extends String> newData) {
+        this.mData.addAll(newData);
+        this.notifyItemRangeInserted(this.mData.size() - newData.size(), newData.size());
+        this.compatibilityDataSizeChanged(newData.size());
+    }
+
+    public void replaceData(@NonNull Collection<? extends String> data) {
+        if (data != this.mData) {
+            this.mData.clear();
+            this.mData.addAll(data);
+        }
+
+        this.notifyDataSetChanged();
+    }
+
+    private void compatibilityDataSizeChanged(int size) {
+        int dataSize = this.mData == null ? 0 : this.mData.size();
+        if (dataSize == size) {
+            this.notifyDataSetChanged();
+        }
+
+    }
+
+    @NonNull
+    public List<String> getData() {
+        return this.mData;
+    }
+
+    @Nullable
+    public String getItem(@IntRange(from = 0L) int position) {
+        return position >= 0 && position < this.mData.size() ? this.mData.get(position) : null;
+    }
+
+    static class ViewHolder extends RecyclerView.ViewHolder {
+
+        private RelativeLayout itemRelative;
+        private ImageView img;
+
+        public ViewHolder(@NonNull View itemView) {
+            super(itemView);
+            init(itemView);
+        }
+
+        private void init(View itemView) {
+            itemRelative = itemView.findViewById(R.id.item_item);
+            img = itemView.findViewById(R.id.item_img);
+        }
+
+
+    }
+
+    static class FooterViewHolder extends RecyclerView.ViewHolder {
+
+        private RelativeLayout itemRelative;
+        private ImageView img;
+
+        public FooterViewHolder(@NonNull View itemView) {
+            super(itemView);
+            init(itemView);
+        }
+
+        private void init(View itemView) {
+            itemRelative = itemView.findViewById(R.id.item_item);
+            img = itemView.findViewById(R.id.item_img);
+        }
+
+    }
+
+}

+ 46 - 0
image_grid_lib/src/main/java/com/benyanyi/image_grid_lib/SquareRelativeLayout.java

@@ -0,0 +1,46 @@
+package com.benyanyi.image_grid_lib;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+/**
+ * @author mylove
+ * @date 2021/9/23
+ * @email ben@yanyi.red
+ * @overview
+ */
+public class SquareRelativeLayout extends RelativeLayout {
+    public SquareRelativeLayout(Context context) {
+        super(context);
+    }
+
+    public SquareRelativeLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int widthMeasure = widthMeasureSpec;
+        int heightMeasure = heightMeasureSpec;
+        setMeasuredDimension(View.getDefaultSize(0, widthMeasure), View.getDefaultSize(0, heightMeasure));
+        widthMeasure = MeasureSpec.makeMeasureSpec(widthMeasure, MeasureSpec.EXACTLY);
+        heightMeasure = MeasureSpec.makeMeasureSpec(heightMeasure, MeasureSpec.EXACTLY);
+        if (widthMeasure > heightMeasure) {
+            widthMeasure = heightMeasure;
+        } else {
+            heightMeasure = widthMeasure;
+        }
+        super.onMeasure(widthMeasure, heightMeasure);
+    }
+}

+ 7 - 0
image_grid_lib/src/main/res/layout/benyanyi_frg_img.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.appcompat.widget.AppCompatImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/img"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</androidx.appcompat.widget.AppCompatImageView>

+ 23 - 0
image_grid_lib/src/main/res/layout/benyanyi_img_details.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#000000">
+
+    <androidx.viewpager2.widget.ViewPager2
+        android:id="@+id/view_pager"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <ImageButton
+        android:id="@+id/back"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@null"
+        android:paddingLeft="@dimen/padding20"
+        android:paddingTop="@dimen/padding20"
+        android:paddingRight="@dimen/padding20"
+        android:paddingBottom="@dimen/padding20"
+        android:src="@mipmap/back_white" />
+
+</RelativeLayout>

+ 20 - 0
image_grid_lib/src/main/res/layout/benyanyi_item_img.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.benyanyi.image_grid_lib.SquareRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/item_item"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/item_img"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <ImageView
+        android:id="@+id/item_delete"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:padding="@dimen/dp5"
+        android:src="@mipmap/delete_photo"/>
+
+</com.benyanyi.image_grid_lib.SquareRelativeLayout>

BIN
image_grid_lib/src/main/res/mipmap-xxhdpi/add_photo.png


BIN
image_grid_lib/src/main/res/mipmap-xxhdpi/back_white.png


BIN
image_grid_lib/src/main/res/mipmap-xxhdpi/delete_photo.png


BIN
image_grid_lib/src/main/res/mipmap-xxhdpi/image_default.png


+ 31 - 0
image_grid_lib/src/main/res/values/attrs.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <declare-styleable name="ImageRecycler">
+
+        <!--列表最大长度-->
+        <attr name="android:maxLength" />
+        <!--是否需要添加图片操作-->
+        <attr name="ir_is_add" format="boolean" />
+        <!--添加图片图标-->
+        <attr name="ir_add_res" format="reference" />
+        <!--默认图片-->
+        <attr name="ir_default_res" format="reference" />
+        <!--最小显示个数-->
+        <attr name="ir_min_show_size" format="integer" />
+        <!--是否需要删除图片-->
+        <attr name="ir_show_delete" format="boolean" />
+        <!--删除图标-->
+        <attr name="ir_delete_res" format="reference" />
+        <!--删除图标内边距-->
+        <attr name="ir_delete_padding" format="dimension" />
+        <!--删除图标位置-->
+        <attr name="ir_delete_gravity" format="enum">
+            <enum name="right" value="0" />
+            <enum name="left" value="1" />
+            <enum name="center" value="2" />
+            <enum name="top" value="3" />
+            <enum name="bottom" value="4" />
+        </attr>
+
+    </declare-styleable>
+</resources>

+ 5 - 0
image_grid_lib/src/main/res/values/dimen.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <dimen name="dp5">5dp</dimen>
+    <dimen name="padding20">20dp</dimen>
+</resources>

+ 0 - 8
settings.gradle

@@ -1,11 +1,3 @@
-dependencyResolutionManagement {
-    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
-    repositories {
-        google()
-        mavenCentral()
-        jcenter() // Warning: this repository is going to shut down soon
-    }
-}
 rootProject.name = "ImageGrid"
 include ':app'
 include ':image_grid_lib'