In Android, ShapeableImageView is used to change the shape of your image to circle, diamond, etc. Also, you can set a corner radius to your ImageView. You can do much more by using this ShapeableImageView with minimal code. So in this article, we are going to make a ShapableImageView in android. By implementing this application we will get a basic idea of how editing of photos is done in android applications. Here we will implement two features i.e to cut or round the corners of an image.
What we are going to build in this article?
Here we will be using two images, one image we will edit with XML code and the other with java code. Using SeekBar the user can round or cut all four corners of the image separately. Note that we are going to implement this application using Java language. A sample video is given below to get an idea about what we are going to do in this article.
Step by Step Implementation
Step 1: Creating a new project
- Open a new project.
- We will be working on Empty Activity with language as Java. Leave all other options unchanged.
- You can change the name of the project at your convenience.
- There will be two default files named activity_main.xml and MainActivity.java.
If you don’t know how to create a new project in Android Studio then you can refer to How to Create/Start a New Project in Android Studio?
Step 2: Adding the required dependency
Open Gradle Scripts > build.gradle(module). Go to app > right click > open module settings > dependencies > Add dependency > Library dependency.
Type material in the search bar and click on search. Select the dependency shown in the below image-
Click on sync now to save the changes.
Step 3: Working with the activity_main.xml file
Navigate to the app > res > layout > activity_main.xml and add the below code to that file. Below is the code for the activity_main.xml file.
XML
<? xml version = "1.0" encoding = "utf-8" ?> <!-- Linear layout as parent layout--> < LinearLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "vertical" android:padding = "16dp" android:gravity = "center" tools:context = ".MainActivity" > <!-- text view to show the text "using xml"--> < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Using xml" android:textStyle = "bold" android:textSize = "20sp" android:padding = "12dp" /> <!-- shapable image view--> < com.google.android.material.imageview.ShapeableImageView android:layout_width = "339dp" android:layout_height = "230dp" android:adjustViewBounds = "true" android:scaleType = "centerCrop" android:src = "@drawable/gfg" app:shapeAppearance = "@style/CornerCut" /> <!-- text view to show the text "using java"--> < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Using Java" android:textSize = "20sp" android:textStyle = "bold" android:padding = "12dp" /> <!-- shapable image view--> < com.google.android.material.imageview.ShapeableImageView android:layout_width = "339dp" android:layout_height = "230dp" android:layout_weight = "1" android:id = "@+id/image_View" android:src = "@drawable/gfg" android:adjustViewBounds = "true" android:scaleType = "centerCrop" /> <!-- spinner to provide options of round and cur--> < Spinner android:layout_width = "match_parent" android:layout_height = "wrap_content" android:id = "@+id/sp_family" android:padding = "12dp" android:layout_marginTop = "16dp" /> <!-- seekbar for top left corner--> < SeekBar android:layout_width = "match_parent" android:layout_height = "wrap_content" android:id = "@+id/sb_top_left" android:layout_marginTop = "16dp" /> <!-- seekbar for top right corner--> < SeekBar android:layout_width = "match_parent" android:layout_height = "wrap_content" android:id = "@+id/sb_top_right" android:layout_marginTop = "8dp" /> <!-- seekbar for bottom left corner--> < SeekBar android:layout_width = "match_parent" android:layout_height = "wrap_content" android:id = "@+id/sb_bottom_left" android:layout_marginTop = "8dp" /> <!-- seekbar for bottom right corner--> < SeekBar android:layout_width = "match_parent" android:layout_height = "wrap_content" android:id = "@+id/sb_bottom_right" android:layout_marginTop = "8dp" /> </ LinearLayout > |
Step 4: Working on themes.xml file
Navigate to res > values > themes > themes.xml file and use the below code in it.
XML
<!-- Base application theme. --> < style name = "Theme.ShapableImageView" parent = "Theme.MaterialComponents.DayNight.DarkActionBar" > <!-- Primary brand color. --> < item name = "colorPrimary" >@color/purple_500</ item > < item name = "colorPrimaryVariant" >@color/purple_700</ item > < item name = "colorOnPrimary" >@color/white</ item > <!-- Secondary brand color. --> < item name = "colorSecondary" >@color/teal_200</ item > < item name = "colorSecondaryVariant" >@color/teal_700</ item > < item name = "colorOnSecondary" >@color/black</ item > <!-- Status bar color. --> < item name = "android:statusBarColor" tools:targetApi = "l" >?attr/colorPrimaryVariant</ item > <!-- Customize your theme here. --> </ style > < style name = "CornerCut" parent = "" > < item name = "cornerFamilyTopLeft" >rounded</ item > < item name = "cornerFamilyTopRight" >cut</ item > < item name = "cornerFamilyBottomLeft" >cut</ item > < item name = "cornerFamilyBottomRight" >rounded</ item > < item name = "cornerSizeTopLeft" >50%</ item > < item name = "cornerSizeTopRight" >25%</ item > < item name = "cornerSizeBottomLeft" >25%</ item > < item name = "cornerSizeBottomRight" >50%</ item > </ style > </ resources > |
After executing the above code design of the activity_main.xml file looks like this.
Step 5: Working with the MainActivity.java file
Go to the MainActivity.java file and refer to the following code. Below is the code for the MainActivity.java file. Comments are added inside the code to understand the code in more detail.
Java
package com.example.shapableimageview; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.SeekBar; import android.widget.Spinner; import com.google.android.material.imageview.ShapeableImageView; import com.google.android.material.shape.CornerFamily; import java.util.ArrayList; public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener { // Initialize variable ShapeableImageView imageView; Spinner spFamily; SeekBar sbTopLeft,sbTopRight,sbBottomLeft,sbBottomRight; int cornerFamily= CornerFamily.CUT,topLeft= 0 ,topRight= 0 ,bottomLeft= 0 ,bottomRight= 0 ; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); // assign variable imageView=findViewById(R.id.image_View); spFamily=findViewById(R.id.sp_family); sbTopLeft=findViewById(R.id.sb_top_left); sbTopRight=findViewById(R.id.sb_top_right); sbBottomLeft=findViewById(R.id.sb_bottom_left); sbBottomRight=findViewById(R.id.sb_bottom_right); // Initialize array list ArrayList<String> arrayList= new ArrayList<>(); // add values in array List arrayList.add( "cut" ); arrayList.add( "rounded" ); // set adapter spFamily.setAdapter( new ArrayAdapter<>(MainActivity. this , android.R.layout.simple_spinner_dropdown_item,arrayList)); // Set Listener on spinner spFamily.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { // check condition if (position== 0 ) { // when cut selected cornerFamily=CornerFamily.CUT; } else { // when rounded selected cornerFamily=CornerFamily.ROUNDED; } // create update method updateImage(); } @Override public void onNothingSelected(AdapterView<?> parent) { } }); // set listener on all seekbar sbTopLeft.setOnSeekBarChangeListener( this ); sbTopRight.setOnSeekBarChangeListener( this ); sbBottomRight.setOnSeekBarChangeListener( this ); sbBottomLeft.setOnSeekBarChangeListener( this ); } private void updateImage() { // set appearance imageView.setShapeAppearanceModel(imageView.getShapeAppearanceModel().toBuilder() .setTopLeftCorner(cornerFamily,topLeft) .setTopRightCorner(cornerFamily,topRight) .setBottomLeftCorner(cornerFamily,bottomLeft) .setBottomRightCorner(cornerFamily,bottomRight) .build()); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { switch (seekBar.getId()) { case R.id.sb_top_left: topLeft=progress; break ; case R.id.sb_top_right: topRight=progress; break ; case R.id.sb_bottom_left: bottomLeft=progress; break ; case R.id.sb_bottom_right: bottomRight=progress; break ; } // call update method updateImage(); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } } |
Here is the final output of our application.
Output: