Android generates National Day avatars

Posted by seoreferrals on Wed, 29 Sep 2021 06:26:16 +0200

effect

 

thinking

At first, I wanted to cover the picture with a picture of the national flag, and then adjust the transparency of the picture of the national flag. But the effect is not very good.

  

  Above is a picture of the national flag covered with and two-thirds of the effect. It's not clear enough to cover the head. It's too abrupt if there is no gradient for two-thirds.

Picture transparency adjustment is used

binding.iv.setAlpha(100);//The value range is set to 0-255

setAlpha has been enabled. It is officially given to use setImageAlpha(int) instead

binding.iv.setImageAlpha(100);//The value range is set to 0-255

So the solution is to separate the background color from the five pointed stars. The background color gradually changes from left to right. The five five pointed stars are pulled out separately and placed in the upper left corner of the picture. If you have a better solution, please leave a message.

realization

The first libraries used are glide and picture selection library

//glide
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
//Picture selection frame
implementation 'io.github.lucksiege:pictureselector:v2.7.3-rc08'

  Complete layout

<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/rl"
        android:layout_width="300dp"
        android:layout_height="300dp">

        <ImageView
            android:id="@+id/iv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:scaleType="centerCrop"
            android:src="@mipmap/ic_launcher" />

        <ImageView
            android:layout_width="200dp"
            android:layout_height="match_parent"
            android:background="@drawable/shape_bg" />

        <ImageView
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:src="@drawable/wujiaoxing" />
    </RelativeLayout>

    <Button
        android:id="@+id/btn_choose"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:background="@drawable/shape_bg"
        android:text="change the avatar"
        android:textColor="@color/colorWhite" />

    <Button
        android:id="@+id/btn_save"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:background="@drawable/shape_bg"
        android:text="Save Avatar"
        android:textColor="@color/colorWhite" />
</LinearLayout>

  The most important thing in the layout is the realization of flag gradient background. Here, a simple resource background method is used to realize gradient, shape_bg.xml file is as follows:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <gradient
        android:angle="0"
        android:startColor="@color/colorRed" />
</shape>

  My color value file

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#6200EE</color>
    <color name="colorPrimaryDark">#3700B3</color>
    <color name="colorAccent">#03DAC5</color>

    <color name="colorBlack">#000000</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorLine">#B3ffff</color>
    <color name="colorTransparency">#00000000</color>
    <color name="colorRed">#EE1C25</color>
</resources>

  Please download the picture resources in the project

Main code implementation

Write permission and photo permission need to be added here

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!--Write permission-->
<uses-permission android:name="android.permission.CAMERA" /> <!-- Photographing authority -->

Implementation of dynamic opening permission and saving avatar function

binding.btnSave.setOnClickListener(v -> {
            if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 201);
            } else {
                getDraw();
            }
        });
 private void getDraw() {
        // Get a picture layout
        binding.rl.setDrawingCacheEnabled(true);
        binding.rl.buildDrawingCache();

        mHandler.postDelayed(() -> {
            // To run in a child thread
            final Bitmap bmp = binding.rl.getDrawingCache(); // Get picture
            savePicture(bmp);// Save picture
            binding.rl.destroyDrawingCache(); // Release resources after saving
        }, 100);
    }
@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 201:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    getDraw();
                } else {
                    Toast.makeText(this, "You have rejected the permission application. You may not be able to perform the following operations~", Toast.LENGTH_LONG).show();
                }
                break;
            case 202:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    doCode();
                } else {
                    Toast.makeText(this, "You have rejected the permission application. You may not be able to perform the following operations~", Toast.LENGTH_LONG).show();
                }
                break;
            default:
        }
    }
public void savePicture(Bitmap bm) {
        File file = createImageFile();
        //Rewrite file
        try {
            // write file
            FileOutputStream fos;
            fos = new FileOutputStream(file);
            //Default jpg
            bm.compress(Bitmap.CompressFormat.PNG, 100, fos);
            fos.flush();
            fos.close();
            bm.recycle();
            sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
            Toast.makeText(this, "Saved successfully,Please check in the album!", Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static File createImageFile() {
        File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Pic");
        if (!dir.exists()) {
            boolean isSuccess = dir.mkdirs();
            Log.i("Pic", "Folder creation status--->" + isSuccess);
        }
        return new File(dir.getPath() + File.separator + "img_" + System.currentTimeMillis() + ".png");
    }

Implementation of changing Avatar

//change the avatar
        binding.btnChoose.setOnClickListener(v -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    //If you don't have permission, apply for permission
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 202);
                } else {
                    //You have permission to execute directly without processing docode()
                    doCode();
                }
            } else {
                //If it is less than 6.0, it can be executed directly without applying for permission
                doCode();
            }
        });
private void doCode() {
        PictureSelectorUtils.ofImage(MainActivity.this, REQUEST_CODE_SELECT_USER_ICON);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_SELECT_USER_ICON && resultCode == Activity.RESULT_OK) {
            String userIconPath = PictureSelectorUtils.forResult(resultCode, data);
            if (userIconPath != null) {
                Glide.with(this).load(userIconPath).into(binding.iv);
            }
        }
    }

Related tools used for image selection

public class PictureSelectorUtils {

    public static void ofImage(Activity activity, int requestCode) {
        PictureSelector.create(activity)
                .openGallery(PictureMimeType.ofImage())
                .imageEngine(GlideEngine.createGlideEngine())
                .theme(R.style.PictureSelectorStyle)
                .selectionMode(PictureConfig.SINGLE)
                .enableCrop(false)//Crop
                .isDragFrame(false)// Can I drag the crop box (fixed)
                .withAspectRatio(1, 1)// int clipping scale, such as 16:9 3:2 3:4 1:1, can be customized
                .isCamera(true)//Whether to display the Photo button true or false
                .isGif(true)//Whether to display gif picture true or false
                .previewImage(true)// Can I preview the picture? true or false
                .forResult(requestCode);
    }

    public static String forResult(int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK) {
            // Callback of picture, video and audio selection results
            List<LocalMedia> selectList = PictureSelector.obtainMultipleResult(data);
            if (selectList != null && selectList.size() > 0) {
                return selectList.get(0).getPath();
            }
        }
        return null;
    }
}
public class GlideEngine implements ImageEngine {

    /**
     * Load picture
     *
     * @param context
     * @param url
     * @param imageView
     */
    @Override
    public void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {
        if (!ImageLoaderUtils.assertValidRequest(context)) {
            return;
        }
        Glide.with(context)
                .load(url)
                .into(imageView);
    }

    /**
     * Load network picture adaptation long picture scheme
     * # Note: this method only calls back when loading network pictures
     *
     * @param context
     * @param url
     * @param imageView
     * @param longImageView
     * @param callback      Network picture loading callback listening {link after version 2.5.1 Please use the #OnImageCompleteCallback #}
     */
    @Override
    public void loadImage(@NonNull Context context, @NonNull String url,
                          @NonNull ImageView imageView,
                          SubsamplingScaleImageView longImageView, OnImageCompleteCallback callback) {
        if (!ImageLoaderUtils.assertValidRequest(context)) {
            return;
        }
        Glide.with(context)
                .asBitmap()
                .load(url)
                .into(new ImageViewTarget<Bitmap>(imageView) {
                    @Override
                    public void onLoadStarted(@Nullable Drawable placeholder) {
                        super.onLoadStarted(placeholder);
                        if (callback != null) {
                            callback.onShowLoading();
                        }
                    }

                    @Override
                    public void onLoadFailed(@Nullable Drawable errorDrawable) {
                        super.onLoadFailed(errorDrawable);
                        if (callback != null) {
                            callback.onHideLoading();
                        }
                    }

                    @Override
                    protected 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) {
                                // Load long graph
                                longImageView.setQuickScaleEnabled(true);
                                longImageView.setZoomEnabled(true);
                                longImageView.setDoubleTapZoomDuration(100);
                                longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
                                longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
                                longImageView.setImage(ImageSource.cachedBitmap(resource),
                                        new ImageViewState(0, new PointF(0, 0), 0));
                            } else {
                                // Ordinary picture
                                imageView.setImageBitmap(resource);
                            }
                        }
                    }
                });
    }

    /**
     * Load network picture adaptation long picture scheme
     * # Note: this method only calls back when loading network pictures
     *
     * @param context
     * @param url
     * @param imageView
     * @param longImageView
     * @ obsolete 
     */
    @Override
    public void loadImage(@NonNull Context context, @NonNull String url,
                          @NonNull ImageView imageView,
                          SubsamplingScaleImageView longImageView) {
        if (!ImageLoaderUtils.assertValidRequest(context)) {
            return;
        }
        Glide.with(context)
                .asBitmap()
                .load(url)
                .into(new ImageViewTarget<Bitmap>(imageView) {
                    @Override
                    protected 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) {
                                // Load long graph
                                longImageView.setQuickScaleEnabled(true);
                                longImageView.setZoomEnabled(true);
                                longImageView.setDoubleTapZoomDuration(100);
                                longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
                                longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
                                longImageView.setImage(ImageSource.cachedBitmap(resource),
                                        new ImageViewState(0, new PointF(0, 0), 0));
                            } else {
                                // Ordinary picture
                                imageView.setImageBitmap(resource);
                            }
                        }
                    }
                });
    }

    /**
     * Load album directory
     *
     * @param context   context
     * @param url       Picture path
     * @param imageView Host image ImageView
     */
    @Override
    public void loadFolderImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {
        if (!ImageLoaderUtils.assertValidRequest(context)) {
            return;
        }
        Glide.with(context)
                .asBitmap()
                .load(url)
                .override(180, 180)
                .centerCrop()
                .sizeMultiplier(0.5f)
                .placeholder(R.drawable.picture_image_placeholder)
                .into(new BitmapImageViewTarget(imageView) {
                    @Override
                    protected void setResource(Bitmap resource) {
                        RoundedBitmapDrawable circularBitmapDrawable =
                                RoundedBitmapDrawableFactory.
                                        create(context.getResources(), resource);
                        circularBitmapDrawable.setCornerRadius(8);
                        imageView.setImageDrawable(circularBitmapDrawable);
                    }
                });
    }


    /**
     * Load gif
     *
     * @param context   context
     * @param url       Picture path
     * @param imageView Host image ImageView
     */
    @Override
    public void loadAsGifImage(@NonNull Context context, @NonNull String url,
                               @NonNull ImageView imageView) {
        if (!ImageLoaderUtils.assertValidRequest(context)) {
            return;
        }
        Glide.with(context)
                .asGif()
                .load(url)
                .into(imageView);
    }

    /**
     * Load picture list picture
     *
     * @param context   context
     * @param url       Picture path
     * @param imageView Host image ImageView
     */
    @Override
    public void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {
        if (!ImageLoaderUtils.assertValidRequest(context)) {
            return;
        }
        Glide.with(context)
                .load(url)
                .override(200, 200)
                .centerCrop()
                .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;
    }
}
public class ImageLoaderUtils {
    public static boolean assertValidRequest(Context context) {
        if (context instanceof Activity) {
            Activity activity = (Activity) context;
            return !isDestroy(activity);
        } else if (context instanceof ContextWrapper){
            ContextWrapper contextWrapper = (ContextWrapper) context;
            if (contextWrapper.getBaseContext() instanceof Activity){
                Activity activity = (Activity) contextWrapper.getBaseContext();
                return !isDestroy(activity);
            }
        }
        return true;
    }

    private static boolean isDestroy(Activity activity) {
        if (activity == null) {
            return true;
        }
        return activity.isFinishing() || activity.isDestroyed();
    }
}

Picture selection page custom style

<style name="PictureSelectorStyle" parent="picture.default.style">
        <!--Title block background color-->
        <item name="colorPrimary">@color/colorPrimaryDark</item>
        <!--Status bar background color-->
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <!--Do you want to change the font color of the status bar of the picture list interface to black-->
        <!--<item name="picture.statusFontColor">false</item>-->
        <!--Return key Icon-->
        <!--<item name="picture.leftBack.icon">@drawable/ic_back</item>-->
        <!--Title drop-down arrow-->
        <!--<item name="picture.arrow_down.icon">@drawable/arrow_down</item>-->
        <!--Title pull up arrow-->
        <!--<item name="picture.arrow_up.icon">@drawable/arrow_up</item>-->
        <!--Title Text Color-->
        <!--<item name="picture.title.textColor">@color/basic_ui_action_bar_text</item>-->
        <!--Title Block right text-->
        <!--<item name="picture.right.textColor">@color/basic_ui_action_bar_text</item>-->
        <!--Picture list check style-->
        <!--<item name="picture.checked.style">@drawable/picture_selector_checkbox</item>-->
        <!--Turn on the picture list and check the digital mode-->
        <item name="picture.style.checkNumMode">false</item>
        <!--Select Picture Style 0/9-->
        <item name="picture.style.numComplete">false</item>
        <!--Background color at the bottom of the picture list-->
        <item name="picture.bottom.bg">@color/colorPrimaryDark</item>
        <!--Picture list preview text color-->
        <!--<item name="picture.preview.textColor">@color/picture_selector_preview_text_color</item>-->
        <!--Picture list finished text color-->
        <!-- <item name="picture.complete.textColor">@color/picture_selector_preview_text_color</item>-->
        <!--Number of dots selected in picture background color-->
        <!--<item name="picture.num.style">@drawable/picture_selector_num_oval</item>-->
        <!--Preview interface title text color-->
        <!--<item name="picture.ac_preview.title.textColor">@color/basic_ui_action_bar_text</item>-->
        <!--Preview interface completed text color-->
        <!--<item name="picture.ac_preview.complete.textColor">@color/picture_selector_preview_text_color</item>-->
        <!--Preview interface title bar background color-->
        <item name="picture.ac_preview.title.bg">@color/colorPrimaryDark</item>
        <!--Background color at the bottom of preview interface-->
        <item name="picture.ac_preview.bottom.bg">@color/colorPrimaryDark</item>
        <!--Preview interface return arrow-->
        <!--<item name="picture.preview.leftBack.icon">@drawable/ic_back</item>-->
        <!--Crop page title background color-->
        <!--<item name="picture.crop.toolbar.bg">@color/basic_ui_action_bar_bg</item>-->
        <!--Crop page status bar color-->
        <!--<item name="picture.crop.status.color">@color/basic_ui_action_bar_bg</item>-->
        <!--Crop page title text color-->
        <!--<item name="picture.crop.title.color">@color/basic_ui_action_bar_text</item>-->
        <!--Album folder list check icon-->
        <!--<item name="picture.folder_checked_dot">@drawable/orange_oval</item>-->
    </style>

For Android 10 and above, there are more partition storage restrictions, so for 10 and above, you need to turn on external storage to save the pictures to the album.

android:requestLegacyExternalStorage="true"

The official solution is:

To improve user privacy, direct access to shared / external * storage devices is not recommended. When the application targets * {@ link android.os.Build.VERSION_CODES#Q}, the * path returned by this method is no longer available for direct access* Applications can continue to access content stored on shared / external * storage by migrating to alternatives such as * {@ link Context#getExternalFilesDir(String)}, * {@ link MediaStore}, or {@ link Intent#ACTION_OPEN_DOCUMENT}.

Such a simple National Day avatar is simply completed. In addition to selecting pictures and saving picture codes a little more, the other important thing is the background gradient in the layout.

For detailed code address, please refer to:

Create national day Avatarhttps://github.com/cuiwenju2017/CreateNationalDayHead

Topics: Android