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 boxViewpadding 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 speedscolors, 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();


Post a Comment

0 Comments