Creating a View Class with ball moving animation

1. Add a Sound file bounce_sound.mp3.

2. Add a new java class file BouncingBallView.java. Put following codes in it.


package com.my.animation;

import android.view.View;
import android.content.Context;
import android.media.SoundPool;
import android.media.AudioAttributes;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Color;
import android.graphics.Canvas;

public class BouncingBallView extends View {
    
    private Paint mypaint;
    private SoundPool soundPool;
    private int soundId;
    private boolean isLoaded = false;
    int directionX = 1; // 1 = moving right, -1 = moving left
    int directionY = 1; // 1 = moving down, -1 = moving up
    int speed = 4;
    int radius = 30;
    int distanceX = radius;
    int distanceY = radius;
    int timeX = 0;
    int timeY = 0;
    
    int viewWidth = 0;
    int viewHeight = 0;
    
    public BouncingBallView(Context context) {
        super(context);
        init(context);
    }
    
    // Optional constructor with AttributeSet (for XML attributes)
    public BouncingBallView(Context context, android.util.AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    
    private void init(Context context){
        mypaint = new Paint();
        mypaint.setStyle(Style.FILL);
        mypaint.setColor(Color.RED);
        initializeSoundPool(context);
    }
    
    @Override
    protected void onDraw(Canvas canvas){
        viewWidth = this.getMeasuredWidth();
        viewHeight = this.getMeasuredHeight();
        canvas.drawCircle(distanceX, distanceY, radius, mypaint);
        calculateNewPosition();
        invalidate();
    }
    
    private void initializeSoundPool(Context context) {
        // Create AudioAttributes for SoundPool
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_GAME)  // Use case
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)  // Type of content
                .build();
        
        // Create SoundPool with max streams
        soundPool = new SoundPool.Builder()
                .setMaxStreams(1)  // Maximum number of simultaneous streams
                .setAudioAttributes(audioAttributes)
                .build();
        
        // Load sound file
        soundId = soundPool.load(context, R.raw.bounce_sound, 1);
        
        // Set listener for when sound is loaded
        soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                if (status == 0) {
                    isLoaded = true;
                }
            }
        });
    }
    
    private void playSound() {
        if (isLoaded) {
            // Parameters: soundId, leftVolume, rightVolume, priority, loop, rate
            soundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1.0f);
        }
    }
    
    private void calculateNewPosition(){
        if (distanceX > (viewWidth - radius)){
            timeX = 0; directionX = -1;
            playSound();
        } else if (distanceX < radius){
            timeX = 0; directionX = 1;
            playSound();
        }
        timeX++;
        if (directionX == -1){
            distanceX = viewWidth - radius - speed*timeX;
        } else {
            distanceX = radius + speed*timeX;
        }
        
        if (distanceY > (viewHeight - radius)){
            timeY = 0; directionY = -1;
            playSound();
        } else if (distanceY < radius){
            timeY = 0; directionY = 1;
            playSound();
        }
        timeY++;
        if (directionY == -1){
            distanceY = viewHeight - radius - speed*timeY;
        } else {
            distanceY = radius + speed*timeY;
        }
    }
    
    public void setBallPosition(int x, int y) {
        this.distanceX = Math.max(radius, Math.min(x, viewWidth - radius));
        this.distanceY = Math.max(radius, Math.min(y, viewHeight - radius));
        // Reset timers
        this.timeX = 0;
        this.timeY = 0;
            
        // Redraw
        invalidate();
    }
    
    public void setBallSpeed(int speed) {
        if (speed > 0) {
            this.speed = speed;
            
            // Reset timers
            if (directionX == -1){
                this.timeX= (viewWidth - radius - distanceX)/speed;
            } else {
                this.timeX = (distanceX - radius)/speed;
            }
            if (directionY == -1){
                this.timeY= (viewHeight - radius - distanceY)/speed;
            } else {
                this.timeY = (distanceY - radius)/speed;
            }
        }
    }
    
    // Set the radius of the ball
    public void setBallRadius(int radius) {
        if (radius > 0) {
            this.radius = radius;
            // Adjust current position to stay within bounds
            if (viewWidth > 0 && viewHeight > 0) {
                distanceX = Math.max(radius, Math.min(distanceX, viewWidth - radius));
                distanceY = Math.max(radius, Math.min(distanceY, viewHeight - radius));
            }
            invalidate(); // Redraw with new radius
        }
    }
    
    // Set ball color
    public void setBallColor(int color) {
        mypaint.setColor(color);
        invalidate();
    }
    
    // Reset ball to its initial settings
    public void resetBall() {
        this.speed = 4;
        this.radius = 30;
        mypaint.setColor(Color.RED);
        this.distanceX = radius;
        this.distanceY = radius;
        this.directionX = 1;
        this.directionY = 1;
        this.timeX = 0;
        this.timeY = 0;
        
        invalidate();
    }
    
    // Clean up SoundPool when view is destroyed
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (soundPool != null) {
            soundPool.release();
            soundPool = null;
        }
    }
    
    
}
    

3. Add a Linear Layout. Set id to boxView, padding to 0, set some background color, set height to 300. Convert this to {package name}.BouncingBallView.

4. Add three spinners spinner_speed, spinner_color, and spinner_radius. Add a Button resetBtn.



5. Add a number variable n and three String List speeds, colors, and radii.

6. In onCreate, add values to the lists and display them in the spinners. See image below.

7. In spinner_speed onItemSelected event, use following codes.


binding.boxView.setBallSpeed(Integer.valueOf(speeds.get(_position)));

8. In spinner_color onItemSelected event, use following codes.


int[] ball_colors = new int[]{Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, Color.WHITE};

binding.boxView.setBallColor(ball_colors[_position]);

9. In spinner_radius onItemSelected event, use following codes.


binding.boxView.setBallRadius(Integer.valueOf(radii.get(_position)));

10. In resetBtn onClick event, use following codes.


binding.boxView.resetBall();

Check video below



Comments

Popular posts from this blog

Simple car racing android game in Sketchware

How to enable upload from webview in Sketchware?

Simple Audio recorder app in Sketchware

Retrieve contact list in Sketchware

Creating a Drawing View in Sketchware