Professional Auto-Sliding Layout Slider In Android Java with ViewPager2

Creating a smooth and engaging user experience is crucial for any Android app. One common UI component that helps achieve this is a Professional Auto-Sliding Layout Slider In Android Java. Perfect for highlighting key features, showcasing products, or creating onboarding screens

πŸ”§ Key Features Implemented

  • βœ… ViewPager2-based layout slider
  • βœ… Auto-slide every 4 seconds
  • βœ… Dot indicators with click support
  • βœ… Smooth animations using PageTransformer
  • βœ… Fully customizable titles and descriptions

🧩 Complete Code Overview

1. Image Slider Setup

private int[] images = {
    R.drawable.image_1,
    R.drawable.image_2,
    R.drawable.image_3
};

private String[] titles = {"Title 1", "Title 2", "Title 3"};
private String[] descriptions = {
    "Description for image 1",
    "Description for image 2",
    "Description for image 3"
};

These arrays hold the images, titles, and descriptions for the slider. You can easily replace them with your own assets or data from an API.

2. ViewPager2 Configuration

viewPager = findViewById(R.id.viewPager);
sliderAdapter = new LayoutSliderAdapter(images, titles, descriptions);
viewPager.setAdapter(sliderAdapter);
viewPager.setPageTransformer(new BookPageTransformer());

The LayoutSliderAdapter binds data to each page. You can use any animation class (like BookPageTransformer) to create swipe effects.

3. Dot Indicator Setup

private void setupDots(int count) {
    for (int i = 0; i < count; i++) {
        ImageView dot = new ImageView(this);
        dot.setImageResource(R.drawable.dot_unselected);
        ...
        dotLayout.addView(dot);
    }
    highlightDot(0);
}

Dots are added dynamically and respond to user interaction, allowing manual slide navigation.

4. Auto-Slide Functionality

private void setupLayoutAutoSlide() {
    slideRunnable = () -> {
        int nextItem = (viewPager.getCurrentItem() + 1) % images.length;
        viewPager.setCurrentItem(nextItem, true);
        slideHandler.postDelayed(slideRunnable, DELAY_IN_MILLI_SEC);
    };
    slideHandler.postDelayed(slideRunnable, DELAY_IN_MILLI_SEC);
}

This function enables the ViewPager2 to auto-slide every 4 seconds using a Handler and Runnable.

Complete Code Classes

1. BookPageTransformer.java


public class BookPageTransformer implements ViewPager2.PageTransformer {

    @Override
    public void transformPage(@NonNull View page, float position) {
        if (position < -1) { 
            page.setAlpha(0f);
        } else if (position <= 0) { 
            page.setAlpha(1f); 
            page.setTranslationX(0f);
            page.setPivotX(page.getWidth());
            page.setRotationY(-90f * Math.abs(position));
        } else if (position <= 1) { 
            page.setAlpha(1f); 
            page.setTranslationX(0f); 
            page.setPivotX(0f); 
            page.setRotationY(90f * Math.abs(position)); 
        } else { 
            page.setAlpha(0f); 
        }
    }
}

2. LayoutSliderAdapter.java


public class LayoutSliderAdapter extends RecyclerView.Adapter {

    private int[] images;
    private String[] titles;
    private String[] descriptions;
    private int[] colors;

    public LayoutSliderAdapter(int[] images, String[] titles, String[] descriptions) {
        this.images = images;
        this.titles = titles;
        this.descriptions = descriptions;
        colors = new int[]{R.color.col1,R.color.col2,R.color.col3};
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_slider_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.rootItem.setBackgroundColor(ContextCompat.getColor(holder.rootItem.getContext(),colors[position]));
        holder.imageView.setImageResource(images[position]);
        holder.titleTextView.setText(titles[position]);
        holder.descriptionTextView.setText(descriptions[position]);
    }

    @Override
    public int getItemCount() {
        return images.length;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        LinearLayout rootItem;
        ImageView imageView;
        TextView titleTextView;
        TextView descriptionTextView;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            rootItem = itemView.findViewById(R.id.rootItem);
            imageView = itemView.findViewById(R.id.imageView);
            titleTextView = itemView.findViewById(R.id.titleTextView);
            descriptionTextView = itemView.findViewById(R.id.descriptionTextView);
        }
    }
}

3. ZoomOutPageTransformer.java


package com.alsaeed.imageslider;

import android.view.View;

import androidx.annotation.NonNull;
import androidx.viewpager2.widget.ViewPager2;

public class ZoomOutPageTransformer implements ViewPager2.PageTransformer {

    private static final float MIN_SCALE = 0.85f;
    private static final float MIN_ALPHA = 0.5f;

    @Override
    public void transformPage(@NonNull View page, float position) {
        if (position < -1) { 
            page.setAlpha(0f);
        } else if (position <= 1) {
            // Scale the page
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            float vertMargin = page.getHeight() * (1 - scaleFactor) / 2;
            float horzMargin = page.getWidth() * (1 - scaleFactor) / 2;
            if (position < 0) {
                page.setTranslationX(horzMargin - vertMargin / 2);
            } else {
                page.setTranslationX(-horzMargin + vertMargin / 2);
            }

            // Scale and fade
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);
            page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
        } else {
            page.setAlpha(0f);
        }
    }
}

4. MainActivity.java


public class MainActivity extends AppCompatActivity {

    private ViewPager2 viewPager;
    private LinearLayout dotLayout;
    private final static int DELAY_IN_MILLI_SEC = 4000;

    private int[] images = {
            R.drawable.image_1,
            R.drawable.image_2,
            R.drawable.image_3
    }; // Replace with your images
    private String[] titles = {"Title 1", "Title 2", "Title 3"};
    private String[] descriptions = {
            "Description for image 1",
            "Description for image 2",
            "Description for image 3"
    };

    private LayoutSliderAdapter sliderAdapter;
    private Handler slideHandler;
    private Runnable slideRunnable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager = findViewById(R.id.viewPager);
        dotLayout = findViewById(R.id.dotSignLayout);

        // Set Adapter for ViewPager2
        sliderAdapter = new LayoutSliderAdapter(images, titles, descriptions);
        viewPager.setAdapter(sliderAdapter);

        // Add PageTransformer for animations
        viewPager.setPageTransformer(new BookPageTransformer());

        // Initialize Dots
        setupDots(images.length);

        // Highlight Dot on Page Change
        viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                highlightDot(position);
            }
        });

        // Auto-Slide Functionality
        slideHandler = new Handler(Looper.getMainLooper());
        setupLayoutAutoSlide();
    }

    private void setupDots(int count) {
        for (int i = 0; i < count; i++) { ImageView dot = new ImageView(this); dot.setImageResource(R.drawable.dot_unselected); // Default dot drawable LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT ); params.setMargins(8, 0, 8, 0); dot.setLayoutParams(params); final int index = i; dot.setOnClickListener(v -> {
                viewPager.setCurrentItem(index);
                resetAutoSlide();
            });

            dotLayout.addView(dot);
        }

        highlightDot(0);
    }

    private void highlightDot(int position) {
        for (int i = 0; i < dotLayout.getChildCount(); i++) {
            ImageView dotIv = (ImageView) dotLayout.getChildAt(i);
            if (i == position) {
                dotIv.setImageResource(R.drawable.dot_selected);
            } else {
                dotIv.setImageResource(R.drawable.dot_unselected);
            }
        }
    }

    private void setupLayoutAutoSlide() {
        slideRunnable = new Runnable() {
            @Override
            public void run() {
                int nextItem = (viewPager.getCurrentItem() + 1) % images.length;
                viewPager.setCurrentItem(nextItem, true);
                slideHandler.postDelayed(this, DELAY_IN_MILLI_SEC);
            }
        };
        slideHandler.postDelayed(slideRunnable, DELAY_IN_MILLI_SEC);
    }

    private void resetAutoSlide() {
        slideHandler.removeCallbacks(slideRunnable);
        slideHandler.postDelayed(slideRunnable, DELAY_IN_MILLI_SEC);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        slideHandler.removeCallbacks(slideRunnable);
    }
}

5. activity_main.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!-- ViewPager2 for Image Slider -->
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/dotSignLayout"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- Dots Indicator -->
    <LinearLayout
        android:id="@+id/dotSignLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/viewPager" />

</androidx.constraintlayout.widget.ConstraintLayout>

6. image_slider_item

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/rootItem"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:orientation="vertical"
    android:padding="16dp">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        app:cardCornerRadius="16dp">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="centerCrop"
            android:src="@drawable/image_1" />

    </androidx.cardview.widget.CardView>

    <TextView
        android:id="@+id/titleTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Title"
        android:textColor="@color/black"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/descriptionTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:text="Description"
        android:textColor="@color/black"
        android:textSize="14sp" />

</LinearLayout>


Download Source Code

πŸ›  Tips for Customization

  • βœ… Add fade-in or zoom animations for enhanced UX
  • βœ… Replace static arrays with dynamic content from Firebase or REST API
  • βœ… Use MotionLayout for more advanced transitions
  • βœ… Customize the dot shapes and colors for better brand alignment

πŸš€ Final Thoughts

Using ViewPager2 with auto-scroll and dot indicators is a powerful way to deliver interactive, modern UI components in your Android app. Whether for onboarding, promotional banners, or product showcases, this slider structure is flexible, reusable, and production-ready.

Collapsing Toolbar Layout in Android Java

Introduction
In this tutorial, we will implement a Collapsing Toolbar Layout in Android Java using AppBarLayout and NestedScrollView. The CollapsingToolbarLayout provides a smooth collapsing effect when the user scrolls through a NestedScrollView.

Prerequisites

  • Android Studio installed
  • Basic knowledge of XML and Java/Kotlin
  • A working Android project

Step 1: activity_main.xml

Create an activity_main.xml file with the following code:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBarLayout"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:contentScrim="@color/black"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true"
            app:titleEnabled="true"
            app:expandedTitleTextAppearance="@android:color/transparent">

            <ImageView
                android:id="@+id/headerImage"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:alpha="0.6"
                android:scaleType="centerCrop"
                android:src="@drawable/img"
                app:layout_collapseMode="parallax" />

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@android:color/transparent"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Dark" />

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:id="@+id/nested_scroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:id="@+id/text_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="Your long text here..." />
    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Step 2: MainActivity.java

Modify MainActivity.java to initialize the toolbar and set the collapsing behavior:


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Set up Toolbar
        Toolbar toolbar = findViewById(R.id.toolbar);
        toolbar.setTitle("");
        setSupportActionBar(toolbar);
    

        // Collapsing Toolbar Layout
        CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsingToolbar);
        AppBarLayout appBarLayout = findViewById(R.id.appBarLayout);

        collapsingToolbarLayout.setTitle("");



        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            boolean isShown = true;
            int scrollRange = -1;

            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (scrollRange == -1) {
                    scrollRange = appBarLayout.getTotalScrollRange();
                }

                if (Math.abs(verticalOffset) >= scrollRange) {
                    // Toolbar is fully collapsed
                    Log.d("Alsaeed", "onOffsetChanged: COLLAPSED");
                    collapsingToolbarLayout.setTitle("Toolbar Title");
                    collapsingToolbarLayout.setCollapsedTitleTextColor(Color.RED);

                    isShown = true;
                } else if (verticalOffset == 0) {
                    // Toolbar is fully expanded
                    Log.d("Alsaeed", "onOffsetChanged: EXPANDED");
                    collapsingToolbarLayout.setTitle("");  // Hide title when expanded
                    isShown = false;
                }
            }
        });
    }

 
}

Step 3: Run the Application

  1. Compile and run the app.
  2. Scroll through the content.
  3. Observe the collapsing effect on the toolbar.


Download Source Code

Conclusion

The CollapsingToolbarLayout provides a visually appealing effect for modern UI designs. It enhances user experience by offering a smooth transition between expanded and collapsed toolbar states. You can further customize it with animations, icons, and additional widgets inside the AppBarLayout.

πŸ“· Barcode Scanner App in Android Java

If you’re searching for a simple yet powerful way to create a Barcode Scanner App in Android Java using Android Studio, you’re in the right place! This tutorial will guide you through building a fully functional barcode and QR code scanner using Google’s Mobile Vision API and Android’s CameraSource class.

This project is ideal for retail apps, inventory management systems, attendance apps, and more.

βœ… Features of This Barcode Scanner App

  • Real-time barcode scanning using device camera
  • Supports all barcode formats (QR, UPC, Data Matrix, etc.)
  • Auto-focus enabled for accurate scanning
  • Audio beep tone when a barcode is detected
  • Displays decoded data in a TextView

πŸ› οΈ Tools & Setup Requirements

  • Android Studio
  • Java language
  • Minimum SDK: 21 (Lollipop)
  • Dependencies:
implementation 'com.google.android.gms:play-services-vision:20.1.3'

πŸ“„ Full Java Code for Barcode Scanner (MainActivity.java)

public class MainActivity extends AppCompatActivity {

    private SurfaceView surfaceView;
    private BarcodeDetector barcodeDetector;
    private CameraSource cameraSource;
    private static final int REQUEST_CAMERA_PERMISSION = 201;
    private ToneGenerator toneGen1;
    private TextView barcodeText;
    private String barcodeData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
        surfaceView = findViewById(R.id.surface_view);
        barcodeText = findViewById(R.id.barcode_text);

        initialiseDetectorsAndSources();
    }

    private void initialiseDetectorsAndSources() {
        barcodeDetector = new BarcodeDetector.Builder(this)
                .setBarcodeFormats(Barcode.ALL_FORMATS)
                .build();

        cameraSource = new CameraSource.Builder(this, barcodeDetector)
                .setRequestedPreviewSize(640, 480)
                .setAutoFocusEnabled(true)
                .build();

        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try {
                    if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                        cameraSource.start(surfaceView.getHolder());
                    } else {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.CAMERA},
                                REQUEST_CAMERA_PERMISSION);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
                cameraSource.stop();
            }
        });

        barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
            @Override
            public void release() {}

            @Override
            public void receiveDetections(@NonNull Detector.Detections<Barcode> detections) {
                final SparseArray<Barcode> barcodes = detections.getDetectedItems();

                if (barcodes.size() != 0) {
                    barcodeText.post(() -> {
                        if (barcodes.valueAt(0).email != null) {
                            barcodeData = barcodes.valueAt(0).email.address;
                        } else {
                            barcodeData = barcodes.valueAt(0).displayValue;
                        }

                        barcodeText.setText(barcodeData);
                        toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP, 150);
                    });
                }
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        Objects.requireNonNull(getSupportActionBar()).hide();
        cameraSource.release();
    }

    @Override
    protected void onResume() {
        super.onResume();
        Objects.requireNonNull(getSupportActionBar()).hide();
        initialiseDetectorsAndSources();
    }
}

πŸ” Code Explanation

  1. SurfaceView & CameraSource
    – SurfaceView: Renders the live camera preview.
    – CameraSource: Controls the camera feed and feeds frames into the BarcodeDetector.
  2. BarcodeDetector
    – Set to detect all barcode formats using Barcode.ALL_FORMATS.
  3. Permissions
    – Checks for camera permission before starting the camera. Requests it if not already granted.
  4. ToneGenerator
    – A beep sound plays every time a barcode is successfully detected.
  5. Barcode Processing
    – If the barcode contains an email, it’s extracted separately; otherwise, the display value is shown.
    – Data is updated on the UI thread using post() for safe rendering.
  6. Preview Size
    – Set using .setRequestedPreviewSize(640, 480) for balance between quality and performance.

πŸ“ UI Layout (activity_main.xml)

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <SurfaceView
        android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="480dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

    <TextView
        android:id="@+id/barcode_text"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        app:layout_constraintTop_toBottomOf="@id/surface_view"
        android:layout_marginTop="50dp"
        android:text="Barcode Text"
        android:textSize="25sp"
        android:padding="5dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

πŸ”’ Important Permissions (AndroidManifest.xml)

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true" />

βœ… Conclusion

This guide helped you build a real-time barcode scanner app using Java in Android Studio. You learned how to use SurfaceView, CameraSource, BarcodeDetector, and handle permissions, audio tones, and camera lifecycle.

You can expand this app by:

  • Saving scanned data to a database
  • Opening URLs directly from QR codes
  • Switching between front and back camera


Download Source Code