AndroidImageView实现可选择裁剪删除全屏查看
Posted 宾有为
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AndroidImageView实现可选择裁剪删除全屏查看相关的知识,希望对你有一定的参考价值。
效果图已放在Java版本的文末,功能有选择、裁剪、删除与全屏查看。最近正在学习kotlin,因此干脆做了两个代码版本的demo,后期如果有时间,会在该功能的基础上再加上一些功能,比如朋友圈选择图片的效果
目录
用到的框架:
// 图片裁剪 UCrop
implementation 'com.github.yalantis:ucrop:2.2.5'
// 全屏查看图片 Transferee
implementation 'com.github.Hitomis.transferee:Transferee:v1.1.0'
// 图片加载器
implementation 'com.github.Hitomis.transferee:PicassoImageLoader:1.6.1'
implementation 'com.squareup.picasso:picasso:2.5.2'
// 图片加载器
implementation "com.github.bumptech.glide:glide:4.11.0"
// 工具库
implementation "com.blankj:utilcodex:1.26.0"
// 如果想制作点击多个图片放大可用到这个
// implementation "com.zhy:base-rvadapter:3.0.3"
// 沉侵式标题栏
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
// 图片圆角框架
implementation 'com.makeramen:roundedimageview:2.3.0'
Java版本
1.自定义View
既然是自定义的布局,那第一步就要先把我们的模块先画出来。而我想要的效果,是展示一张图片的同时右上角有一个可以删除图片的按钮(如果想长按图片是删除的话,可以把相关的布局代码省略掉,到时候弄一个长按事件监听(ImageView.setOnLongClickListener())即可)
删除按钮在图片的右上角,我们可以使用 ConstraintLayout 布局使其位于指定位置,至于默认图片用的是android自带的图片,真不是懒得找
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="100dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="90dp"
android:layout_height="90dp"
android:src="@android:drawable/ic_menu_add"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<ImageView
android:id="@+id/cancel"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@android:drawable/ic_menu_close_clear_cancel"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
新建一个类用以绑定自定义的布局,在这个项目中,不需要为自定义的ImageView设置新的属性,便不再定义declare-styleable,xml布局的第一个Layout是ConstraintLayout,也要把继承的对象修改为ConstraintLayout
/**
* Created by BinJianxin on 2021/5/03
*/
public class CustomImageView extends ConstraintLayout
private ImageView imageView;
private ImageView cancel;
public CustomImageView(Context context)
this(context, null);
public CustomImageView(Context context, @Nullable AttributeSet attrs)
this(context, attrs, 0);
public CustomImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
View inflate = LayoutInflater.from(context).inflate(/**自定义的Layout布局**/, this);
cancel = inflate.findViewById(R.id.cancel);
imageView = inflate.findViewById(R.id.imageView);
public void setCancelOnClick(OnClickListener click)
cancel.setOnClickListener(click);
public void setImageOnClick(OnClickListener click)
imageView.setOnClickListener(click);
public void setImageURI(Uri uri)
imageView.setImageURI(uri);
public void showCancel(boolean b)
if (b)
cancel.setVisibility(View.VISIBLE);
else
cancel.setVisibility(View.INVISIBLE);
public void setImageResource(int res)
imageView.setImageResource(res);
到这里,自定义的样式已经差不多了,接下来就是使用
在需要用到的地方将其加入
<自定义CustomImageView类的路径.CustomImageView
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@android:drawable/ic_menu_close_clear_cancel"/>
在对应的Activity绑定其id,设置点击事件
image.setCancelOnClick(new View.OnClickListener()
@Override
public void onClick(View view)
image.showCancel(false);
image.setImageResource(android.R.drawable.ic_menu_add);
);
int CODE = 100;
image.setImageOnClick(new View.OnClickListener()
@Override
public void onClick(View view)
// 申请权限
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(MainActivity.this,new String[]Manifest.permission.READ_EXTERNAL_STORAGE,1);
else
// 跳转到选择图片界面
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent,CODE);
);
读写权限被Google列为危险权限,动态申请权限分别需要在Java代码与需要在 AndroidManifest.xml 文件分别进行声明
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
当一张图片被选中后,可以通过 onActivityResult 方法得到这个选中照片的相关信息
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK)
switch (requestCode)
case CODE:
uri = data.getData();
if (uri != null)
image.setImageURI(uri);
break;
这样一来,图片就能正常显示出来了,点击右上角小叉叉便可以将其恢复成最初滴样子啦
看了上面效果图,oh my god,这图片四四方方,上下又不对称,原本一个正方形的展示框让他以一个长方形的形状出现的我的面前。俗话说:丑的一批。这时候我们就可以在该布局上进行点缀,让它稍微好看点,不好看的东西客户可不会为此买单喔~
2.裁剪
图片裁剪用的是GitHub有着 Start 10.7k的UCrop框架,详情请看:GitHub
使用裁剪框架需要将执行裁剪操作的Activity加入到 AndroidManifest.xml 的 application 标签内
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
加入为大家准备好的裁剪方法:
/**
* @param uri 所选图片的路径
* @param requestCode UCrop裁剪后在onActivityResult执行的代码
* @param hideBottomControls 隐藏UCrop下边控制栏
* @param showCropGrid 设置是否显示裁剪网格
* @param showCropFrame 设置是否显示裁剪边框
* @用途 图片裁剪
*/
public void startCrop(Uri uri, int requestCode, boolean hideBottomControls, boolean showCropGrid, boolean showCropFrame)
UCrop.Options options = new UCrop.Options();
//裁剪后图片保存在文件夹中
Uri destinationUri = Uri.fromFile(new File(MainActivity.this.getExternalCacheDir(), "uCrop.jpg"));
UCrop uCrop = UCrop.of(uri, destinationUri);//第一个参数是裁剪前的uri,第二个参数是裁剪后的uri
uCrop.withAspectRatio(1, 1);//设置裁剪框的宽高比例
//下面参数分别是缩放,旋转,裁剪框的比例
options.setAllowedGestures(UCropActivity.ALL, UCropActivity.NONE, UCropActivity.ALL);
options.setToolbarTitle("裁剪图片");//设置标题栏文字
options.setCropGridStrokeWidth(1);//设置裁剪网格线的宽度(我这网格设置不显示,所以没效果)
options.setCropFrameStrokeWidth(1);//设置裁剪框的宽度
options.setMaxScaleMultiplier(3);//设置最大缩放比例
options.setHideBottomControls(hideBottomControls);//隐藏下边控制栏
options.setShowCropGrid(showCropGrid); //设置是否显示裁剪网格
options.setShowCropFrame(showCropFrame); //设置是否显示裁剪边框(true为方形边框)
// options.setToolbarWidgetColor(Color.parseColor("#000000"));//标题字的颜色以及按钮颜色
// options.setDimmedLayerColor(Color.parseColor("#000000"));//设置裁剪外颜色
// options.setToolbarColor(Color.parseColor("#ffffff")); // 设置标题栏颜色
// options.setStatusBarColor(Color.parseColor("#ffffff"));//设置状态栏颜色
// options.setCropGridColor(Color.parseColor("#ffffff"));//设置裁剪网格的颜色
// options.setCropFrameColor(Color.parseColor("#ffffff"));//设置裁剪框的颜色
uCrop.withOptions(options);
uCrop.start(MainActivity.this, requestCode);
在得到图片的时候进行调用
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK)
switch (requestCode)
case CODE:
Uri uri1 = data.getData();
if (uri1 != null)
// 选择图片后对图片进行裁剪
startCrop(uri1,UCrop.REQUEST_CROP,false,false,true);
break;
// 裁剪图片后的操作
case UCrop.REQUEST_CROP:
uri = UCrop.getOutput(data);
image.setImageURI(uri);
image.showCancel(true);
break;
这个时候就可以得到以下效果
3.图片全屏
图片点击放大、查看使用的是GitHub Start 达2.6K的 transferee 框架,详情请看:GitHub
当我们点击图片时,对图片进行放大且全屏,就要根据一个 Uri 来进行判断,如果是null,那我们不执行查看图片,而执行选择图片,反之,点击即查看图片
image.setImageOnClick(new View.OnClickListener()
@Override
public void onClick(View view)
if (uri == null)
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(MainActivity.this,new String[]Manifest.permission.READ_EXTERNAL_STORAGE,1);
else
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent,CODE);
else
transferee = Transferee.getDefault(MainActivity.this);
TransferConfig recyclerTransConfig = TransferConfig.build()
.setImageLoader(GlideImageLoader.with(getApplicationContext()))
.bindImageView(image.getImageView(),uri.toString());
transferee.apply(recyclerTransConfig).show();
);
使用 ImageLoader 需要注意的一点就是在读取第一张图片的时候会有缓存,如果不清理,放大后的照片除了第一张和你预想的一样,基本不会相同,解决办法就是设置 ImageLoader 不缓存或者在执行 ImageLoader 相关操作前先清除一遍缓存
GlideImageLoader.with(getApplicationContext()).clearCache();
自此,点击图片放大功能完成
这有一个问题还是得说一下哈
点击放大后主Activity顶部状态栏就变样了,操作的时候标题栏会陷入标签栏或标签栏颜色被改动,
针对类似问题,只需要两步
(1)在Activity的onCreate方法加上
ImmersionBar.with(this).statusBarColor(R.color.colorPrimary).init();
(2)在Activity的xml第一层layout标签内加上
android:fitsSystemWindows="true"
显示是显示出来了,但是看着咋还那么丑呢???
图片展示的不好看,不能说是图片不好看所导致,即使图片是世界级摄影师所拍摄,展示的不好,可能也真就不好看了。
那么,如何弄得好看点呢?
我们可以对展示图片的ImageView进行一点修饰,比如说加点半径?就像下面这样
原图:
加了半径后:
哈哈,毫无违和感
好了,接下来又到用人家框架的时刻了
对图片的操作我们可以使用 roundedimageview 框架,
自定义的View,我们也只需要将对应的 ImageView 改为 RoundedImageView
private com.makeramen.roundedimageview.RoundedImageView imageView;
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/imageView"
android:layout_width="90dp"
android:layout_height="90dp"
android:src="@android:drawable/ic_menu_add"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
再加一个方法用以设置半径
public void setRadiu(int radiu)
imageView.setCornerRadius(radiu);
调用之后就变成这样啦
以及,这个样子
到此便完成了所有工作
Kotlin版
上面的Java版本已经把我能说的话几乎说完了,kotlin版本我就不在多说
CustomImageView 类
class CustomImageView : ConstraintLayout
var cancel: ImageView? = null;
var imageView: RoundedImageView? = null
// constructor(context: Context) : this(context,attribSet)
constructor(context: Context, attributeSet: AttributeSet) : this(context, attributeSet,0)
constructor(context: Context, attributeSet: AttributeSet, defValue: Int) : super(
context,
attributeSet,
defValue
)
val inflate =
LayoutInflater.from(context).inflate(R.layout.activity_custom_image_view, this)
cancel = inflate.findViewById<View>(R.id.cancel) as ImageView?
imageView = inflate.findViewById<View>(R.id.imageView) as RoundedImageView?
val obtainStyledAttributes =
context.obtainStyledAttributes(attributeSet, R.styleable.CustomImageView)
val indexCount = obtainStyledAttributes.indexCount
for (index in 0..indexCount)
val index1 = obtainStyledAttributes.getIndex(index)
when (index1)
R.styleable.CustomImageView_showCancel ->
val boolean = obtainStyledAttributes.getBoolean(
R.styleable.CustomImageView_showCancel,
false
)
if (boolean)
cancel!!.visibility = View.VISIBLE
else
cancel!!.visibility = View.INVISIBLE
fun showCancel(boolean: Boolean)
if (boolean)
cancel?.visibility = View.VISIBLE
else
cancel?.visibility = View.INVISIBLE
fun setImageOnClick(onClickListener: OnClickListener)
imageView?.setOnClickListener(onClickListener)
fun setCancelOnClick(onClickListener: OnClickListener)
cancel?.setOnClickListener(onClickListener)
fun setImageResource(res : Int)
imageView?.setImageResource(res)
fun setImageUri(uri: Uri)
imageView?.setImageURI(uri)
fun getImage():RoundedImageView
return imageView as RoundedImageView
fun setRadiu(radiu : Float)
imageView?.setCornerRadius(radiu)
MainActivity 类
class MainActivity : AppCompatActivity()
var CODE = 101
var uri:Uri ?= null
override fun onCreate(savedInstanceState: Bundle以上是关于AndroidImageView实现可选择裁剪删除全屏查看的主要内容,如果未能解决你的问题,请参考以下文章
Android ImageView 将较小的图像缩放到具有灵活高度的宽度,而不会裁剪或扭曲
网页保存PDF 保留文字 删除页面 裁剪页面 删除不需要的内容