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

仿朋友圈相册图片选择以及画廊效果「建议收藏」仿朋友圈相册图片选择以及画廊效果1.效果展示2.导入相关第三方库依赖3.编写选择图片页面a.编写布局b.编写Activityc.相册选择工具类部分代码d.相册4宫图适配器4.编写画廊页面a.编写画廊页面b.编写Activityc.画廊适配器5.源码1.效果展示该demo适配Android6、7、10。画廊效果,支持缩放效果。视频展示:(等我B站视频审核通过再来修改)部分截图:文章有点长,如果没时间就拉到最底下下载源码,再给个一键三联哈(* ̄︶ ̄)2.导入相关第三方库依赖站在巨人的肩膀上,

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

1.效果展示

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

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

部分截图:在这里插入图片描述
在这里插入图片描述
文章有点长,如果没时间就拉到最底下下载源码,再给个一键三联哈(* ̄︶ ̄)

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

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

在这里插入图片描述

    //图片加载框架
    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.编写布局

<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

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.相册选择工具类部分代码

/** * @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宫图适配器

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.编写画廊页面

<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


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.画廊适配器

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

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刷新效果

 @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方法

 ItemTouchHelper.Callback callback = new RecycleItemTouchHelper(mPhotoAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(mRvPhoto);

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

6.源码

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Python暴力激活成功教程wifi密码

    Python暴力激活成功教程wifi密码今天给大家分享一个使用Python激活成功教程WiFi密码的代码,这个代码也是非常简单,这里需要用Python中的pywifi这个库,所以需要在DOS命令下安装这个库,同样使用pipinstallpywifi,很简单就安装成功了,我用的是Python3,所以各位看的时候需要注意这一点。接下来我们一步一步分析主要代码,后面同样附上完整的代码。对了,需要注意一点,就是电脑必须是要用无线网卡的。首先我们…

  • java实现发送邮件功能

    java实现发送邮件功能java实现发送邮件功能电子邮件开发在后台中是普遍存在的现象和功能,比如用户注册,系统自动发送一封电子邮件到用户邮箱;再比如密码找回,系统会自动把密码发送到用户邮箱;……等等,所以作为一名java程序员,还是有必要学会这项技能的。我是一名安卓开发人员,我们都知道在客户端和后台交互数据的时候用到了Http协议,那么相应的,邮箱传输也有自己的一套协议,如SMTP,POP3,IMAP。在原生的javaJ

  • Jenkins 系列教程-史上最简单Jenkins教程,教你一天学会使用Jenkins利器「建议收藏」

    Jenkins 系列教程-史上最简单Jenkins教程,教你一天学会使用Jenkins利器「建议收藏」一、安装Git安装yum命令安装:yuminstall-ygit安装结果验证:git–versionNode安装(非必须)链接:Centos安装nodejsMaven安装文档:链接:Centos安装MavenJDK安装链接:Linux下安装javaJDK&部署ZookeeperJenKins安装jenkins官网:https://www.jenkins.io/zh/访问Jenkins的官方网站的downdolad

  • Swift3创建数组

    Swift3创建数组数组是由一组类型相同的元素构成的有序数据集合。数组中的集合元素是有序的,而且可以重复出现。1 数组创建在Swift语言中,数组的类型格式为:Array或[ElementType]其中Array中的ElementType表示数组的类型,是泛型写法。[ElementType]是一种简写方式。两者表示的功能是一样的,我们更偏向于使用简写形式,本书里所有数组类型都是使用简写形式。下

  • cmd跑绿色代码_cmd装逼代码-cmd命令,装逼

    cmd跑绿色代码_cmd装逼代码-cmd命令,装逼本教程分享:《cmd装逼代码》如何使用命令提示符装逼事先声明,如果你不知道打开windows的命令行工具,我是绝对不会告诉你是用windows+R,然后键入cmd打开的windows自带的命令行工具很强大,毕竟计算机一开始都是以键入命令的方式来操作的,但现如今计算机的发展,许多在过去需要去记大量命令才能完成的操作,现如今通过傻瓜式的点选都可以完成。作为一名有逼格的程序员,在计算机如今图形界面…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号