前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >仿朋友圈相册图片选择以及画廊效果「建议收藏」

仿朋友圈相册图片选择以及画廊效果「建议收藏」

作者头像
全栈程序员站长
发布2022-08-31 17:48:06
1K0
发布2022-08-31 17:48:06
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

仿朋友圈相册图片选择以及画廊效果

1.效果展示

该demo适配Android 6、7、10。画廊效果,支持缩放效果。 视频展示:

安卓实现仿微信朋友圈以及画廊效果

部分截图:

文章有点长,如果没时间就拉到最底下下载源码,再给个一键三联哈(* ̄︶ ̄)

2.导入相关第三方库依赖

站在巨人的肩膀上,敲代码便可事半功倍。

代码语言:javascript
复制
    //图片加载框架
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    //黄油刀
    implementation 'com.jakewharton:butterknife:10.2.3'
    annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'
    // 图片选择器
    api 'com.zhihu.android:matisse:0.5.3-beta3'
    //动态权限申请
    implementation 'com.yanzhenjie:permission:2.0.3'
    //rv
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    //rv第三方万能适配器
    implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'
    //顶部标题栏
    implementation 'com.wuhenzhizao:titlebar:1.0.7'
    //图片缩放框架
    implementation 'com.github.chrisbanes:PhotoView:2.3.0'

3.编写选择图片页面

a.编写布局

代码语言:javascript
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:orientation="vertical">

    <com.wuhenzhizao.titlebar.widget.CommonTitleBar
        android:id="@+id/title"
        style="@style/StyleTitle"
        app:centerText="@string/wechat_zone"
        app:leftType="none"
        app:showBottomLine="true" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@mipmap/home_bg_float"
        android:orientation="vertical">

        <EditText
            android:id="@+id/et_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@null"
            android:focusable="true"
            android:gravity="top"
            android:hint="@string/hint_text"
            android:lineSpacingExtra="9dp"
            android:lineSpacingMultiplier="1.2"
            android:maxLength="400"
            android:minHeight="200dp"
            android:paddingLeft="15dp"
            android:paddingTop="20dp"
            android:paddingRight="15dp"
            android:paddingBottom="20dp"
            android:textColor="@color/text_primary"
            android:textColorHint="@color/dialog_cancel_text_color"
            android:textSize="13sp" />

        <TextView
            android:id="@+id/tv_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:layout_marginRight="15dp"
            android:layout_marginBottom="5dp"
            android:text="0/400"
            android:textColor="@color/dialog_cancel_text_color"
            android:textSize="14sp" />

        <View style="@style/StyleLine" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_photo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/dp_10" />
    </LinearLayout>

    <Button
        android:id="@+id/btn_submit"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_margin="@dimen/dp_10"
        android:background="@mipmap/home_bg_float"
        android:text="@string/submit" />
</LinearLayout>

b.编写Activity

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity implements OnItemClickListener, OnItemChildClickListener, TextWatcher { 
   
    @BindView(R.id.rv_photo)
    RecyclerView mRvPhoto;
    @BindView(R.id.activity_main)
    LinearLayout mActivityMain;
    @BindView(R.id.title)
    CommonTitleBar mTitle;
    @BindView(R.id.et_content)
    EditText mEtContent;
    @BindView(R.id.tv_count)
    TextView mTvCount;
    @BindView(R.id.btn_submit)
    Button mBtnSubmit;
    private PhotoAdapter mPhotoAdapter;
    //点击item的时候通过判断是否有照片文件list,有值跳画廊ac,没值弹框
    private List<PhotoVo> mPhotoList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) { 
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        initViews();
    }

    private void initViews() { 
   
        mPhotoAdapter = new PhotoAdapter();
        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);
        mRvPhoto.setLayoutManager(gridLayoutManager);
        mPhotoAdapter.setList(dealWithList(mPhotoList));
        mRvPhoto.setAdapter(mPhotoAdapter);
        mPhotoAdapter.setOnItemClickListener(this);
        mPhotoAdapter.setOnItemChildClickListener(this);
        mEtContent.addTextChangedListener(this);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 
   
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) { 
   
            switch (requestCode) { 
   
                case CameraAlbumUtil.REQUEST_CODE_TAKE_PHOTO://相机回调
                    String contentPath = CameraAlbumUtil.getInstance().getCameraPath();
                    mPhotoList.add(new PhotoVo(contentPath, new File(contentPath)));
                    mPhotoAdapter.setList(dealWithList(mPhotoList));
                    break;
                case CameraAlbumUtil.REQUEST_CODE_ALBUM://相册回调
                    List<String> pathList;
                    if (data != null) { 
   
                        pathList = Matisse.obtainPathResult(data);
                        if (pathList.size() > 0) { 
   
                            for (int i = 0; i < pathList.size(); i++) { 
   
                                String s = pathList.get(i);
                                Uri uri = FileUtil.getImageContentUri(this, pathList.get(i));
                                mPhotoList.add(new PhotoVo(s, FileUtil.changeFile(this, uri)));
                            }
                            mPhotoAdapter.setList(dealWithList(mPhotoList));
                        }
                    }

                    break;
            }
        }
    }

    private List<PhotoVo> dealWithList(List<PhotoVo> list) { 
   
        List<PhotoVo> newList = new ArrayList<>();
        if (list != null) newList.addAll(list);
        if (newList.size() < 4) newList.add(null);//最多只能4张
        return newList;
    }

    @Override
    public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view,
                            int position) { 
   
        if (adapter.getData().get(position) == null) { 
   
            CameraAlbumUtil.getInstance().showCameraAlbumDialog(this);
        } else { 
   
            Intent intent = new Intent(this, GalleryActivity.class);
            intent.putExtra("photoList", (Serializable) mPhotoList);
            startActivity(intent);
        }
    }

    @Override
    public void onItemChildClick(@NonNull BaseQuickAdapter adapter, @NonNull View view,
                                 int position) { 
   
        if (view.getId() == R.id.iv_delete) { 
   //删除按钮
            mPhotoList.remove(mPhotoList.get(position));
            mPhotoAdapter.setList(dealWithList(mPhotoList));
        }
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) { 
   

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) { 
   

    }

    @Override
    public void afterTextChanged(Editable s) { 
   
        mTvCount.setText(s.length() + "/400");
    }


}

c.相册选择工具类部分代码

代码语言:javascript
复制
/** * @author LJW * @create 2020/11/16 * @Describe 打开相机相册工具类 */
public class CameraAlbumUtil { 
   
    public static final int REQUEST_CODE_TAKE_PHOTO = 1000;
    public static final int REQUEST_CODE_ALBUM = 1001;
    private static final String ALBUM = "ALBUM";
    private static MediaStoreCompat mediaStoreCompat;

    private CameraAlbumUtil() { 
   
    }

    /** * * @param activity */
    public void showCameraAlbumDialog(Activity activity) { 
   
        DialogUtil dialogUtil = new DialogUtil();
        dialogUtil.setClickListenerInterface(new DialogUtil.ClickListenerInterface() { 
   
            @Override
            public void onAlbumClickListener() { 
   
                getPermission(activity, ALBUM, REQUEST_CODE_ALBUM);
            }

            @Override
            public void onCameraClickListener() { 
   
                getPermission(activity, "", REQUEST_CODE_TAKE_PHOTO);
            }
        });
        dialogUtil.showDialog(activity);
    }

    /** * @param activity 哪个界面 * @param type 打开相册传"ALBUM",其他传"" * @param requestCode 请求码 */
    public void getPermission(Activity activity, String type, int requestCode) { 
   
        if (!AndPermission.hasPermissions(activity, Permission.CAMERA, Permission.WRITE_EXTERNAL_STORAGE)) { 
   
            AndPermission.with(activity)
                    .runtime()
                    .permission(Permission.CAMERA, Permission.WRITE_EXTERNAL_STORAGE)
                    .onGranted(permissions -> { 
   
                        switch (type) { 
   
                            case ALBUM:
                                gotoAlbum(activity, requestCode);
                                break;
                            default:
                                gotoCamera(activity, requestCode);
                                break;
                        }
                    })
                    .onDenied(permissions -> { 
   
                    })
                    .start();
        } else { 
   
            switch (type) { 
   
                case ALBUM:
                    gotoAlbum(activity, requestCode);
                    break;
                default:
                    gotoCamera(activity, requestCode);
                    break;
            }
        }
    }

    /** * 打开相机 * * @param activity * @param requestCode 请求码 */
    public void gotoCamera(Activity activity, int requestCode) { 
   
        mediaStoreCompat = new MediaStoreCompat(activity);
        mediaStoreCompat.setCaptureStrategy(new CaptureStrategy(false,
                "com.example.viewpagegallery.fileProvider",
                "preventpro"));
        mediaStoreCompat.dispatchCaptureIntent(activity, requestCode);
    }

    /** * 打开相册 * * @param activity * @param requestCode 请求码 */
    public void gotoAlbum(Activity activity, int requestCode) { 
   
        Matisse.from(activity)
                .choose(MimeType.ofAll())
                .countable(true)
                .maxSelectable(4)
                .gridExpectedSize(activity.getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
                .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
                .thumbnailScale(0.85f)
                .imageEngine(new GlideEngine())
                .showPreview(false) // Default is `true`
                .capture(false) //是否提供拍照功能
                .captureStrategy(new CaptureStrategy(true, "com.example.viewpagegallery.fileProvider"))//存储到哪里
                .forResult(requestCode);
    }

    /** * 获取拍照后的地址,方便上传使用 * * @return */
    public String getCameraPath() { 
   
        return mediaStoreCompat.getCurrentPhotoPath();
    }

    public static class SingleInstance { 
   
        private static CameraAlbumUtil cameraAlbumSingle = new CameraAlbumUtil();
    }

    public static CameraAlbumUtil getInstance() { 
   
        return SingleInstance.cameraAlbumSingle;
    }
}

d.相册4宫图适配器

代码语言:javascript
复制
public class PhotoAdapter extends BaseQuickAdapter<PhotoVo, BaseViewHolder> { 
   
    public PhotoAdapter() { 
   
        super(R.layout.item_phtoto);
    }

    @Override
    protected void convert(@NotNull BaseViewHolder holder, PhotoVo photoVo) { 
   
        if (photoVo != null && photoVo.getFile() != null) { 
   //空图
            CornerTransform transformation = new CornerTransform(getContext(), ScreenUtils.dip2px(getContext(), 10));
            Glide.with(getContext()).load(photoVo.getFile().getPath())
                    .transform(transformation)
                    .into((ImageView) holder.getView(R.id.iv_img));
            holder.setVisible(R.id.iv_empty, false);
            holder.setVisible(R.id.iv_delete, true);
            holder.setVisible(R.id.iv_img, true);
        } else { 
   //有图
            holder.setVisible(R.id.iv_empty, true);
            holder.setGone(R.id.iv_delete, true);
            holder.setGone(R.id.iv_img, true);
        }

        holder.getView(R.id.iv_delete).setOnClickListener(new View.OnClickListener() { 
   
            @Override
            public void onClick(View v) { 
   
                setOnItemChildClick(v, holder.getAdapterPosition());
            }
        });
    }
}

4.编写画廊页面

a.编写画廊页面

代码语言:javascript
复制
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFC0CB"
    android:clipChildren="false">

    <com.wuhenzhizao.titlebar.widget.CommonTitleBar
        android:id="@+id/title"
        style="@style/StyleTitle"
        app:centerText="@string/gallery_title"
        app:showBottomLine="true" />

    <com.example.viewpagegallery.MyViewPager
        android:id="@+id/viewPager"
        android:layout_width="240dp"
        android:layout_height="400dp"
        android:layout_centerInParent="true"
        android:clipChildren="false" />

    <TextView
        tools:text="1/4"
        android:id="@+id/tv_num_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center_horizontal|bottom"
        android:layout_marginBottom="30dp"
        android:textColor="#909090"
        android:textSize="18sp" />
</RelativeLayout>

b.编写Activity

代码语言:javascript
复制
public class GalleryActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener { 
   

    @BindView(R.id.viewPager)
    MyViewPager viewPager;
    @BindView(R.id.tv_num_title)
    TextView tvNumTitle;
    @BindView(R.id.title)
    CommonTitleBar mTitle;
    private GalleryAdapter mGalleryAdapter;
    private List<PhotoVo> mPhotoList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) { 
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gallery);
        ButterKnife.bind(this);
        initViews();
    }

    @SuppressLint("DefaultLocale")
    private void initViews() { 
   
        mTitle.setListener((v, action, extra) -> { 
   
            switch (action) { 
   
                case CommonTitleBar.ACTION_LEFT_BUTTON:
                    finish();
                    break;
                case CommonTitleBar.ACTION_RIGHT_TEXT:
                    break;
            }
        });
        mPhotoList = (List<PhotoVo>) getIntent().getSerializableExtra("photoList");
        mGalleryAdapter = new GalleryAdapter(mPhotoList, this);
        tvNumTitle.setText(String.format("%d/%d", 1, mPhotoList.size()));
        viewPager.setAdapter(mGalleryAdapter);
        viewPager.addOnPageChangeListener(this);
        viewPager.setPageTransformer(true, new RotationPageTransForm());
        viewPager.setOffscreenPageLimit(2); //下面会说到
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
   

    }

    @Override
    public void onPageSelected(int position) { 
   
        // 每当页数发生改变时重新设定一遍当前的页数和总页数
        tvNumTitle.setText((position + 1) + "/" + mPhotoList.size());
    }

    @Override
    public void onPageScrollStateChanged(int state) { 
   

    }
}

c.画廊适配器

代码语言:javascript
复制
public class GalleryAdapter extends PagerAdapter { 
   
    private List<PhotoVo> mPhotos;
    private Context mContext;

    public GalleryAdapter(List<PhotoVo> mPhotos, Context mContext) { 
   
        this.mPhotos = mPhotos;
        this.mContext = mContext;
    }

    @Override
    public int getCount() { 
   
        return mPhotos.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { 
   
        return view == object;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) { 
   
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_gallery, container, false);
        PhotoView photoView = view.findViewById(R.id.photo_view);
        Glide.with(mContext).load(mPhotos.get(position).getFile().getPath())
                .into(photoView);
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 
   
        container.removeView((View) object);
    }
}

5.新增拖拽效果,高度模仿微信朋友圈

a.增加拖拽处理类RecycleItemTouchHelper

代码语言:javascript
复制
public class RecycleItemTouchHelper extends ItemTouchHelper.Callback { 
   
    private static final String TAG = "RecycleItemTouchHelper";
    private final ItemTouchHelperCallback helperCallback;

    public RecycleItemTouchHelper(ItemTouchHelperCallback helperCallback) { 
   
        this.helperCallback = helperCallback;
    }

    /** * 设置滑动类型标记 * * @param recyclerView * @param viewHolder * @return 返回一个整数类型的标识,用于判断Item那种移动行为是允许的 */
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 
   
        Log.e(TAG, "getMovementFlags: ");
        int drafFlags = 0;
        int swipeFlags;
        //START 右向左 END左向右 LEFT 向左 RIGHT向右 UP向上
        //如果某个值传0,表示不触发该操作,次数设置支持上下拖拽,支持向右滑动
        if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { 
   
            drafFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            swipeFlags = 0;
        }
        return makeMovementFlags(drafFlags, 0);
    }

    /** * Item是否支持长按拖动 * * @return true 支持长按操作 * false 不支持长按操作 */
    @Override
    public boolean isLongPressDragEnabled() { 
   
        return super.isLongPressDragEnabled();
    }

    /** * Item是否支持滑动 * * @return true 支持滑动操作 * false 不支持滑动操作 */
    @Override
    public boolean isItemViewSwipeEnabled() { 
   
        return super.isItemViewSwipeEnabled();
    }

    /** * 拖拽切换Item的回调 * * @param recyclerView * @param viewHolder * @param target * @return 如果Item切换了位置,返回true;反之,返回false */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 
   
        Log.e(TAG, "onMove: ");
        helperCallback.onMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    /** * 滑动Item * * @param viewHolder * @param direction Item滑动的方向 */
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 
   
        Log.e(TAG, "onSwiped: ");
        helperCallback.onItemDelete(viewHolder.getAdapterPosition());
    }

    /** * Item被选中时候回调 * * @param viewHolder * @param actionState 当前Item的状态 * ItemTouchHelper.ACTION_STATE_IDLE 闲置状态 * ItemTouchHelper.ACTION_STATE_SWIPE 滑动中状态 * ItemTouchHelper#ACTION_STATE_DRAG 拖拽中状态 */
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { 
   
        super.onSelectedChanged(viewHolder, actionState);
    }

    @Override
    public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { 
   
        super.clearView(recyclerView, viewHolder);
    }

    public interface ItemTouchHelperCallback { 
   
        void onItemDelete(int positon);

        void onMove(int fromPosition, int toPosition);
    }
}

然后在PhotoAdapter实现ItemTouchHelperCallback接口 然后重写接口里面的这两个类达到移动后的item刷新效果

代码语言:javascript
复制
 @Override
    public void onItemDelete(int positon) { 
   
        getData().remove(positon);
        notifyItemRemoved(positon);
    }

    @Override
    public void onMove(int fromPosition, int toPosition) { 
   
        Collections.swap(getData(),fromPosition,toPosition);//交换数据
        notifyItemMoved(fromPosition,toPosition);
    }

b.在MainAcitivity里面绑定itemTouchHelper方法

代码语言:javascript
复制
 ItemTouchHelper.Callback callback = new RecycleItemTouchHelper(mPhotoAdapter);
 ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
 itemTouchHelper.attachToRecyclerView(mRvPhoto);

这样既可实现item的拖拽效果啦

6.源码

创作不易,给博主一键三联,可免费领取博主的爱心代码(详情联系QQ:2872960735)(* ̄︶ ̄) 源码下载地址

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/142884.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 仿朋友圈相册图片选择以及画廊效果
  • 1.效果展示
  • 2.导入相关第三方库依赖
  • 3.编写选择图片页面
    • a.编写布局
      • b.编写Activity
        • c.相册选择工具类部分代码
          • d.相册4宫图适配器
          • 4.编写画廊页面
            • a.编写画廊页面
              • b.编写Activity
                • c.画廊适配器
                • 5.新增拖拽效果,高度模仿微信朋友圈
                  • a.增加拖拽处理类RecycleItemTouchHelper
                    • b.在MainAcitivity里面绑定itemTouchHelper方法
                    • 6.源码
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档