Android 九宫格布局(图片上传、预览)

前言:
利用RecyclerView展示朋友圈UI布局,包含展示、预览、删除等功能

效果图
在这里插入图片描述
在这里插入图片描述

1、在项目app\build.gradle添加依赖

    //图片加载implementation 'com.github.bumptech.glide:glide:4.8.0'//初始化控件找IDimplementation 'com.jakewharton:butterknife:10.2.1'annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'//图片选择器implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.5.8'//权限请求implementation 'com.hjq:xxpermissions:6.5'

build.gradle主项目中添加:maven { url ‘https://jitpack.io’ }

allprojects {repositories {google()jcenter()maven { url 'https://jitpack.io' }}
}

具体使用:
①、MainActivity:

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";@BindView(R.id.edit)EditText edit;@BindView(R.id.recycler)RecyclerView recycler;private SelectPlotAdapter adapter;private ArrayList<String> allSelectList;//所有的图片集合private ArrayList<String> categoryLists;//查看图片集合private List<LocalMedia> selectList = new ArrayList<>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);if (null == allSelectList) {allSelectList = new ArrayList();}if (null == categoryLists) {categoryLists = new ArrayList();}Tools.requestPermissions(MainActivity.this);initAdapter();}private void initAdapter() {//最多9张图片adapter = new SelectPlotAdapter(this, 9);recycler.setLayoutManager(new GridLayoutManager(this, 3));adapter.setImageList(allSelectList);recycler.setAdapter(adapter);adapter.setListener(new SelectPlotAdapter.CallbackListener() {@Overridepublic void add() {//可添加的最大张数=9-当前已选的张数int size = 9 - allSelectList.size();Tools.galleryPictures(MainActivity.this, size);}@Overridepublic void delete(int position) {allSelectList.remove(position);categoryLists.remove(position);adapter.setImageList(allSelectList);//再set所有集合}@Overridepublic void item(int position, List<String> mList) {selectList.clear();for (int i = 0; i < allSelectList.size(); i++) {LocalMedia localMedia = new LocalMedia();localMedia.setPath(allSelectList.get(i));selectList.add(localMedia);}//①、图片选择器自带预览PictureSelector.create(MainActivity.this).themeStyle(R.style.picture_default_style).isNotPreviewDownload(true)//是否显示保存弹框.imageEngine(GlideEngine.createGlideEngine()) // 选择器展示不出图片则添加.openExternalPreview(position, selectList);//②:自定义布局预览//Tools.startPhotoViewActivity(MainActivity.this, categoryLists, position);}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {// 结果回调List<LocalMedia> selectList = PictureSelector.obtainMultipleResult(data);showSelectPic(selectList);}}private void showSelectPic(List<LocalMedia> result) {for (int i = 0; i < result.size(); i++) {String path;//判断是否10.0以上if (Build.VERSION.SDK_INT >= 29) {path = result.get(i).getAndroidQToPath();} else {path = result.get(i).getPath();}allSelectList.add(path);categoryLists.add(path);Log.e(TAG, "图片链接: " + path);}adapter.setImageList(allSelectList);}@OnClick({R.id.upload})public void onClick(View view) {switch (view.getId()) {case R.id.upload:String content = edit.getText().toString();if (TextUtils.isEmpty(content)) {Toast.makeText(this, "请输入上传内容", Toast.LENGTH_LONG).show();return;}if (allSelectList.size() == 0) {Toast.makeText(this, "请选择图片进行上传", Toast.LENGTH_LONG).show();return;}Log.e(TAG, "内容: " + content);Log.e(TAG, "图片: " + allSelectList.toString());break;}}
}

②、SelectPlotAdapter 展示适配器

public class SelectPlotAdapter extends RecyclerView.Adapter<SelectPlotAdapter.SelectHolder> {private Context mContext;private List<String> mediaDtoList;//最大图片张数private int picMax;public void setImageList(List<String> mList) {this.mediaDtoList = mList;notifyDataSetChanged();}public SelectPlotAdapter(Context mContext, int max) {this.mContext = mContext;this.picMax = max;}@Overridepublic SelectHolder onCreateViewHolder(ViewGroup parent, int viewType) {return new SelectHolder(LayoutInflater.from(mContext).inflate(R.layout.item_gallery, parent, false));}@Overridepublic void onBindViewHolder(SelectHolder holder, final int position) {//当前位置大于图片数量并且小于最大减1if (position >= mediaDtoList.size() && position <= (picMax - 1)) {//显示添加图片按钮、并隐藏删除按钮Tools.showGlide(mContext,holder.gallery,"");holder.delete.setVisibility(View.GONE);} else {//显示本地或网络图片,并显示删除按钮Tools.showGlide(mContext,holder.gallery,mediaDtoList.get(position));holder.delete.setVisibility(View.VISIBLE);}//按钮删除事件holder.delete.setOnClickListener(v -> {//传入position删除第几张listener.delete(position);});holder.gallery.setOnClickListener(v -> {//添加新图片点击事件(回调activity)if (position >= mediaDtoList.size() && position <= (picMax - 1)) {listener.add();} else {//点击查看图片事件,并将最新list传入actiuvitylistener.item(position, mediaDtoList);}});}@Overridepublic int getItemCount() {if (mediaDtoList == null || mediaDtoList.size() == 0) {return 1;} else {return this.mediaDtoList.size() >= picMax ? picMax : this.mediaDtoList.size() + 1;}}public class SelectHolder extends RecyclerView.ViewHolder {private ImageView gallery;private ImageView delete;public SelectHolder(View itemView) {super(itemView);gallery = itemView.findViewById(R.id.im_show_gallery);delete = itemView.findViewById(R.id.iv_del);}}private CallbackListener listener;public void setListener(CallbackListener listener) {this.listener = listener;}public interface CallbackListener {//图片添加事件void add();//删除第几张图片void delete(int position);//图片点击void item(int position, List<String> mList);}
}

由于Butterknife需使用Java 8故需在依赖处添加

  // Butterknife requires Java 8.compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}

③、自定义图片预览MyImageAdapter(需要则添加)

public class MyImageAdapter extends PagerAdapter {private List<String> imageUrls;private Activity mContext;public MyImageAdapter(Activity context, List<String> imageUrls) {this.imageUrls = imageUrls;this.mContext = context;}@Overridepublic Object instantiateItem(ViewGroup container, int position) {String url = imageUrls.get(position);PhotoView photoView = new PhotoView(mContext);Tools.showGlide(mContext, photoView, url);container.addView(photoView);photoView.setOnClickListener(v -> mContext.finish());return photoView;}@Overridepublic int getCount() {return imageUrls != null ? imageUrls.size() : 0;}@Overridepublic boolean isViewFromObject(View view, Object object) {return view == object;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView((View) object);}@Overridepublic int getItemPosition(Object object) {return POSITION_NONE;}
}

④、工具类Tools:

public class Tools {/*** 请求权限*/public static void requestPermissions(final AppCompatActivity activity) {XXPermissions.with(activity)// 可设置被拒绝后继续申请,直到用户授权或者永久拒绝//.constantRequest()// 支持请求6.0悬浮窗权限8.0请求安装权限//.permission(Permission.SYSTEM_ALERT_WINDOW, Permission.REQUEST_INSTALL_PACKAGES)// 不指定权限则自动获取清单中的危险权限.permission(Permission.Group.STORAGE).permission(Permission.CAMERA).request(new OnPermission() {@Overridepublic void hasPermission(List<String> granted, boolean all) {}@Overridepublic void noPermission(List<String> denied, boolean quick) {}});}/*** 打开图库*/public static void openGallery(AppCompatActivity activity, int maxSize) {PictureSelector.create(activity).openGallery(PictureMimeType.ofImage())//全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()//.theme()//主题样式(不设置为默认样式) 也可参考demo values/styles下 例如:R.style.picture.white.style.maxSelectNum(maxSize)// 最大图片选择数量 int.minSelectNum(1)// 最小选择数量 int.imageSpanCount(3)// 每行显示个数 int.imageEngine(GlideEngine.createGlideEngine())//.selectionMode()// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE//.isPreviewImage(true)// 是否可预览图片 true or false//.isPreviewVideo()// 是否可预览视频 true or false//.freeStyleCropEnabled() // 是否可播放音频 true or false.isCamera(false)// 是否显示拍照按钮 true or false//.imageFormat(PictureMimeType.PNG)// 拍照保存图片格式后缀,默认jpeg.isZoomAnim(true)// 图片列表点击 缩放效果 默认true//.setOutputCameraPath("/CustomPath")// 自定义拍照保存路径,可不填.isEnableCrop(true)// 是否裁剪 true or false//.isCompress(true)// 是否压缩 true or false//.withAspectRatio()// int 裁剪比例 如16:9 3:2 3:4 1:1 可自定义//.hideBottomControls()// 是否显示uCrop工具栏,默认不显示 true or false//.isGif(false)// 是否显示gif图片 true or false//.compressSavePath(getPath())//压缩图片保存地址.freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false//.circleDimmedLayer()// 是否圆形裁剪 true or false//.showCropFrame()// 是否显示裁剪矩形边框 圆形裁剪时建议设为false   true or false//.showCropGrid()// 是否显示裁剪矩形网格 圆形裁剪时建议设为false    true or false//.isOpenClickSound(false)// 是否开启点击声音 true or false//.selectionData()// 是否传入已选图片 List<LocalMedia> list//.isPreviewEggs()// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中) true or false//.cutOutQuality(90)// 裁剪压缩质量 默认90 int.minimumCompressSize(100)// 小于100kb的图片不压缩//.synOrAsy(true)//同步true或异步false 压缩 默认同步//.cropImageWideHigh()// 裁剪宽高比,设置如果大于图片本身宽高则无效 int//.rotateEnabled(true) // 裁剪是否可旋转图片 true or false.scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false//.videoQuality()// 视频录制质量 0 or 1 int//.videoMaxSecond(15)// 显示多少秒以内的视频or音频也可适用 int//.videoMinSecond(10)// 显示多少秒以内的视频or音频也可适用 int//.recordVideoSecond()//视频秒数录制 默认60s int.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code}/*** 打开拍照*/public static void takingPictures(AppCompatActivity activity) {PictureSelector.create(activity).openCamera(PictureMimeType.ofImage()).forResult(PictureConfig.REQUEST_CAMERA);}/*** 打开图库+拍照按钮*/public static void galleryPictures(AppCompatActivity activity, int maxSize) {PictureSelector.create(activity).openGallery(PictureMimeType.ofImage())//全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()//.theme()//主题样式(不设置为默认样式) 也可参考demo values/styles下 例如:R.style.picture.white.style.maxSelectNum(maxSize)// 最大图片选择数量 int.minSelectNum(1)// 最小选择数量 int.imageEngine(GlideEngine.createGlideEngine()).imageSpanCount(3)// 每行显示个数 int.isCamera(true)// 是否显示拍照按钮 true or false.isZoomAnim(true)// 图片列表点击 缩放效果 默认true//.isEnableCrop(true)// 是否裁剪 true or false.isCompress(true)// 是否压缩 true or false.minimumCompressSize(100)// 小于100kb的图片不压缩.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code}/*** 加载圆角图片** @param context 上下文* @param view    图片控件* @param url     网络图片地址*/public static void showGlide(Context context, ImageView view, String url) {RequestOptions options = new RequestOptions().error(R.mipmap.ic_add).transform(new GlideRoundTransform(context,5));Glide.with(context).load(url).apply(options).into(view);}/*** 跳转到查看图片界面* 上下文、list、点击的位置*/public static void startPhotoViewActivity(Activity context, ArrayList<String> mList, int position) {Intent intent = new Intent(context, PhotoViewActivity.class);Bundle bundle = new Bundle();bundle.putStringArrayList("list", mList);intent.putExtras(bundle);intent.putExtra("position", position);context.startActivity(intent);}
}

⑤、自定义PhotoViewActivity(需要则添加):

public class PhotoViewActivity extends AppCompatActivity {@BindView(R.id.viewpager)ViewPager viewpager;@BindView(R.id.mTvImageCount)TextView mTvImageCount;//点击的下标private int currentPosition;private List<String> urlLists;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_photo_view);ButterKnife.bind(this);initData();}private void initData() {if (null == urlLists) {urlLists = new ArrayList<>();}//获得点击的位置currentPosition = getIntent().getIntExtra("position", 0);//图片集合urlLists = getIntent().getStringArrayListExtra("list");MyImageAdapter adapter = new MyImageAdapter(this, urlLists);viewpager.setAdapter(adapter);viewpager.setCurrentItem(currentPosition);mTvImageCount.setText(currentPosition + 1 + "/" + urlLists.size());viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Overridepublic void onPageSelected(int position) {mTvImageCount.setText(position + 1 + "/" + urlLists.size());}@Overridepublic void onPageScrollStateChanged(int state) {}});}
}

⑥:布局相关文件:
1、activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><EditTextandroid:id="@+id/edit"android:layout_width="match_parent"android:layout_height="200dp"android:gravity="top"android:hint="请输入上传内容"android:padding="15dp" /><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recycler"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:layout_margin="15dp" /><Buttonandroid:id="@+id/upload"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="20dp"android:text="提交" />
</LinearLayout>

2、item_gallery.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="100dp"android:layout_height="100dp"android:layout_marginBottom="5dp"android:paddingRight="5dp"><ImageViewandroid:id="@+id/im_show_gallery"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerCrop" /><ImageViewandroid:id="@+id/iv_del"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentEnd="true"android:paddingBottom="5dp"android:paddingStart="5dp"android:src="@drawable/picture_icon_delete_photo" /></RelativeLayout>

picture_icon_delete_photo为自带删除按钮,如需更换自行修改

3、activity_photo_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#000000"tools:context=".PhotoViewActivity"><androidx.viewpager.widget.ViewPagerandroid:layout_centerInParent="true"android:id="@+id/viewpager"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="30dp"android:layout_marginBottom="30dp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#ffffff"android:textSize="16sp"android:id="@+id/mTvImageCount"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:layout_marginBottom="5dp"android:text="1/1" /></RelativeLayout>

⑦、app\src\main\AndroidManifest.xml添加相应权限

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

扩展相关
1、图片圆角GlideRoundTransform:

public class GlideRoundTransform extends BitmapTransformation {private static float radius = 0f;public GlideRoundTransform(Context context) {this(context, 4);}/*** 圆角大小* @param context* @param dp*/public GlideRoundTransform(Context context, int dp) {//super(context);this.radius = Resources.getSystem().getDisplayMetrics().density * dp;}@Overrideprotected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {Bitmap bitmap = TransformationUtils.centerCrop(pool, toTransform, outWidth, outHeight);return roundCrop(pool, bitmap);}private static Bitmap roundCrop(BitmapPool pool, Bitmap source) {if (source == null) return null;Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);if (result == null) {result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);}Canvas canvas = new Canvas(result);Paint paint = new Paint();paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));paint.setAntiAlias(true);RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());canvas.drawRoundRect(rectF, radius, radius, paint);return result;}public String getId() {return getClass().getName() + Math.round(radius);}@Overridepublic void updateDiskCacheKey(MessageDigest messageDigest) {}
}

2、图片选择器加载图片失败GlideEngine:

public class GlideEngine implements ImageEngine {/*** 加载图片** @param context* @param url* @param imageView*/@Overridepublic void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {Glide.with(context).load(url).into(imageView);}/*** 加载网络图片适配长图方案* # 注意:此方法只有加载网络图片才会回调** @param context* @param url* @param imageView* @param longImageView* @param callback      网络图片加载回调监听 {link after version 2.5.1 Please use the #OnImageCompleteCallback#}*/@Overridepublic void loadImage(@NonNull Context context, @NonNull String url,@NonNull ImageView imageView,SubsamplingScaleImageView longImageView, OnImageCompleteCallback callback) {Glide.with(context).asBitmap().load(url).into(new ImageViewTarget<Bitmap>(imageView) {@Overridepublic void onLoadStarted(@Nullable Drawable placeholder) {super.onLoadStarted(placeholder);if (callback != null) {callback.onShowLoading();}}@Overridepublic void onLoadFailed(@Nullable Drawable errorDrawable) {super.onLoadFailed(errorDrawable);if (callback != null) {callback.onHideLoading();}}@Overrideprotected void setResource(@Nullable Bitmap resource) {if (callback != null) {callback.onHideLoading();}if (resource != null) {boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(),resource.getHeight());longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE);imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE);if (eqLongImage) {// 加载长图longImageView.setQuickScaleEnabled(true);longImageView.setZoomEnabled(true);longImageView.setPanEnabled(true);longImageView.setDoubleTapZoomDuration(100);longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);longImageView.setImage(ImageSource.bitmap(resource),new ImageViewState(0, new PointF(0, 0), 0));} else {// 普通图片imageView.setImageBitmap(resource);}}}});}/*** 加载网络图片适配长图方案* # 注意:此方法只有加载网络图片才会回调** @param context* @param url* @param imageView* @param longImageView* @ 已废弃*/@Overridepublic void loadImage(@NonNull Context context, @NonNull String url,@NonNull ImageView imageView,SubsamplingScaleImageView longImageView) {Glide.with(context).asBitmap().load(url).into(new ImageViewTarget<Bitmap>(imageView) {@Overrideprotected void setResource(@Nullable Bitmap resource) {if (resource != null) {boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(),resource.getHeight());longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE);imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE);if (eqLongImage) {// 加载长图longImageView.setQuickScaleEnabled(true);longImageView.setZoomEnabled(true);longImageView.setPanEnabled(true);longImageView.setDoubleTapZoomDuration(100);longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);longImageView.setImage(ImageSource.bitmap(resource),new ImageViewState(0, new PointF(0, 0), 0));} else {// 普通图片imageView.setImageBitmap(resource);}}}});}/*** 加载相册目录** @param context   上下文* @param url       图片路径* @param imageView 承载图片ImageView*/@Overridepublic void loadFolderImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {Glide.with(context).asBitmap().load(url).apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder)).into(new BitmapImageViewTarget(imageView) {@Overrideprotected void setResource(Bitmap resource) {RoundedBitmapDrawable circularBitmapDrawable =RoundedBitmapDrawableFactory.create(context.getResources(), resource);circularBitmapDrawable.setCornerRadius(8);imageView.setImageDrawable(circularBitmapDrawable);}});}/*** 加载gif** @param context   上下文* @param url       图片路径* @param imageView 承载图片ImageView*/@Overridepublic void loadAsGifImage(@NonNull Context context, @NonNull String url,@NonNull ImageView imageView) {Glide.with(context).asGif().load(url).into(imageView);}/*** 加载图片列表图片** @param context   上下文* @param url       图片路径* @param imageView 承载图片ImageView*/@Overridepublic void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {Glide.with(context).load(url).apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder)).into(imageView);}private GlideEngine() {}private static GlideEngine instance;public static GlideEngine createGlideEngine() {if (null == instance) {synchronized (GlideEngine.class) {if (null == instance) {instance = new GlideEngine();}}}return instance;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/250710.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

unity3d 中场景不显示了

应该是把Layers下面的Nothing打开了

python九宫格图片的原理~

原理 1、用Python制作的九宫格图像生成器包装exe文件&#xff0c;用户无需部署安装Python的开发环境&#xff0c;即可在当地运行该程序&#xff0c;快速生成九宫格图像。 2、用PIL库不断画小区域&#xff0c;切下来存储成新的小图片。 实例 假设每一个格子的宽和高分别是w、…

用纯css实现一个图片拼接九宫格

<style> body{ margin: 0; padding: 0; // 设定居中 display: flex; justify-content: center; align-items: center; height: 100vh; } .container{ width: 300px; height: 300px; display: flex; // 子盒子布局&#xff0c;要让子盒子之间有间隙就把宽高设大一些。 jus…

九宫格

一、定义 什么叫.9.PNG呢&#xff0c;这是安卓开发里面的一种特殊的图片 这种格式的图片在android 环境下具有自适应调节大小的能力。 &#xff08;1&#xff09;允许开发人员定义可扩展区域&#xff0c;当需要延伸图片以填充比图片本身更大区域时&#xff0c;可扩展区的内容被…

自定义九宫格图片

注&#xff1a;此Demo只是为了学习自定义相关知识&#xff0c;不建议在项目中引用使用. 已实现功能&#xff1a; 1.可设置每行显示的列数、删除图标、加号图片、设置padding&#xff0c;删除图标与图片的间距&#xff0c; 行和列的间距以及删除图标的大小; 2.match_parent模式…

基础复习——图形定制——图形Drawable——形状图形——九宫格图片——状态列表图形...

Drawable类型表达了各种各样的图形&#xff0c;包括图片、色块、画板、背景等。 包含图片在内的图形文件放在res目录的各个drawable目录下&#xff0c;其中drawable目录一般保存描述性的XML文件&#xff0c;而图片文件一般放在具体分辨率的drawable目录下。 各视图的background…

html用九张图片做出九宫图,用ps如何将九张照片做成九宫格?

如何用PS将九张照片做成九宫格&#xff0c;并且随时可以更换呢。下面跟搞设计一起来做一下吧。 ↑ 首先准备好九张照片 ↑ 打开PS&#xff0c;新建一个1000x1000的文件 ↑ 选择矩形工具 ↑ 创建一个300x300的矩形 ↑ 随便填个颜色&#xff0c;把图层命名为1 ↑ 选择视图-新建参…

Grid 布局实现九宫格图片动画

前言 &#x1f44f;Grid 布局实现九宫格&#xff0c;background-position设置背景图像起始位置&#xff0c;速速来Get吧~ &#x1f947;文末分享源代码。记得点赞关注收藏&#xff01; 1.实现效果 2.实现步骤 定义css变量&#xff1a;九宫格中每个宫格的长/宽为w&#xff0c…

九宫格拼图

九宫格拼图的实现&#xff1a; 效果为下图所示&#xff0c;实现拼图的完成&#xff0c;这里附上完整的代码&#xff0c;需要注意的是在产生随机的初始状态时&#xff0c;是随机两两交换&#xff0c;才能保证其一直是1-9的这样的情况&#xff0c;其他具体响应的设计在程序注释中…

【Android】-- 图形(形状图形、状态列表图形、九宫格图片)

一、图形Drawable Drawable类型表达了各种各样的图形&#xff0c;包括图片、色块、画板、背景等。 包含图片在内的图形文件放在res目录的各个drawable目录下&#xff0c;其中drawable目录一般保存描述性的XML文件&#xff0c;而图片文件一般放在具体分辨率的drawable目录下。…

Python生成九宫格图片

一、前言 大家在朋友圈应该看到过用一张图片以九宫格的方式显示&#xff0c;效果大致如下&#xff1a; 要实现上面的效果非常简单&#xff0c;我们只需要截取图片的九个区域即可。今天我们就要带大家使用Python来实现一下九宫格图片的生成。在开始之前&#xff0c;我们需要安…

【设计模式】策略模式

【设计模式】策略模式 1.什么是策略模式2.&#x1f330;一整坨代码实现策略模式重构代码 附录 1.什么是策略模式 策略模式是一种行为设计模式&#xff0c; 它能让你定义一系列算法&#xff0c; 并将每种算法分别放入独立的类中&#xff0c; 以使算法的对象能够相互替换。 2.&…

520表白浪漫的句子文案用便签记下来

在5月20日也就是520这个美好的情人节里&#xff0c;相信有很多年轻的情侣们都要出来约会了&#xff0c;一起度过这个浪漫的节日。并且520这个节日也是非常适合向心仪的人表白的哦&#xff0c;其实有不少小伙伴都是想要向某个人表白的&#xff0c;但是当面表白又不太好意思&…

文艺-浪漫句子

宇宙级别的浪漫 这朵世间最美好的玫瑰&#xff0c;星尘为泥&#xff0c;银河滋养。永远不会枯萎&#xff0c;永远在沉静宇宙中盛放。这是我要给你的&#xff0c;宇宙级别的浪漫——自珩给习清看玫瑰星云的时候说 当丁达尔效应出现的时候光就有了形状&#xff0c;这是我要给你…

HACKER KID: 1.0.1实战演练

文章目录 HACKER KID: 1.0.1实战演练一、前期准备1、相关信息 二、信息收集1、端口扫描2、访问网站3、扫描目录4、查看源码5、请求参数6、burpsuite批量请求7、编辑hosts文件8、DNS区域传输9、编辑hosts10、访问网站11、注册账号12、burpsuite抓包13、XML注入14、解密15、登录网…

Android系统中的Binder通信机制分析(6)- Binder通信机制详解

声明 其实对于Android系统Binder通信的机制早就有分析的想法&#xff0c;记得2019年6、7月份Mr.Deng离职期间约定一起对其进行研究的&#xff0c;但因为我个人问题没能实施这个计划&#xff0c;留下些许遗憾…文中参考了很多书籍及博客内容&#xff0c;可能涉及的比较多先不具…

Linux I2C驱动分析4 - GPIO模拟I2C

一. 前言 在嵌入式开发中&#xff0c;由于芯片的I2C接口有限&#xff0c;或者出于硬件画板的方便&#xff0c;我们都需要将普通的GPIO模拟I2C接口使用。出于对这样的需求&#xff0c;Linux-2.6.x已经有相关代码了&#xff0c;Linux-3.x有标准的内核选项支持该功能&#xff0c;内…

如何搭建与使用FTP服务器

一、概述 目前用作搭建FTP服务器端的软件有很多&#xff0c;比如 Vsftpd、ProFTPD、PureFTPd、Wuftpd、ServerU、Filezilla Server等&#xff0c;这里使用Vsftpd进行搭建。 vsftpd 是“very secure ftp daemon”的首字母缩写&#xff0c;它是一款在Linux发行版中最受推崇的免…

【Redis】聊一下Redis的哨兵机制

在上一篇文章中&#xff0c;我们学习了数据库的Redis的主从集群复制模式&#xff0c;如果从库出现问题&#xff0c;那么其他主从库还可以处理读写请求&#xff0c;但是如果主库宕机&#xff0c;写请求从库处理不了&#xff0c;整个系统就不可用了&#xff0c;虽然只处理只读请求…

windows的cmd命令窗口介绍

1.打开cmd 1.1.方式一 左下角搜索&#xff1a;“运行” -> 打开 输入"cmd" -> 确定 1.2.方式二 直接使用快捷键 windows r 即可打开 然后输入cmd&#xff0c;点击确认 1.3.方式三 打开文件管理器&#xff0c;输入cmd&#xff0c;回车 即可在该文件路径下…