How to properly render images when two Rects intersect in my game? - android

So basically the game works like this, Whenever the fire makes contact with the icecream, I want a different icecream to be drawn on the screen. A smaller one that would resemble a "melted" appearance. But whenever the icecream and fire collide, the games ends when it's not suppose to.
This is the code that renders the iceCream
private void renderIceCream(Painter g) {
if (iceCream3) {
g.drawImage(Assets.iceCream3, (int) iceCream.getX(), (int) iceCream.getY(), ICECREAM_WIDTH, IC3_HEIGHT);
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream3 = false;
iceCream2 = true;
}
}
if (iceCream2) {
g.drawImage(Assets.iceCream2, (int) iceCream.getX(), (int) iceCream.getY() + 25, ICECREAM_WIDTH, IC2_HEIGHT);
//
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream2 = false;
iceCream1 = true;
}
}
if (iceCream1) {
g.drawImage(Assets.iceCream1, (int) iceCream.getX(), (int) iceCream.getY() + 50, ICECREAM_WIDTH, IC1_HEIGHT);
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream1 = false;
iceCream.melted();
}
}
}
This is the whole class
package rect.draw.gametest.model.state;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.view.GestureDetector;
import android.view.MotionEvent;
import java.util.ArrayList;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.view.MotionEvent;
import android.widget.Toast;
import rect.draw.gametest.Assets;
import rect.draw.gametest.GameMainActivity;
import rect.draw.gametest.model.Fire;
import rect.draw.gametest.model.IceCream;
import rect.draw.gametest.model.util.Painter;
public class PlayState extends State {
private IceCream iceCream;
private Fire fire;
private int fireX = 400;
private int fireY = 0;
private int cloudX = 0;
private int cloudY = 100;
private float duckDuration = .6f;
private int playerY;
private int playerScore = 0;
private static final int BLOCK_HEIGHT = 50;
private static final int BLOCK_WIDTH = 20;
private int fireSpeed = -200;
private static int ICECREAM_WIDTH = 38;
private static int IC1_HEIGHT = 77;
private static int IC2_HEIGHT= 102;
private static int IC3_HEIGHT = 127;
private static int FIRE_WIDTH = 75;
private static int FIRE_HEIGHT = 75;
public boolean iceCream1,iceCream2,iceCream3,durationEnded;
private float recentTouchY;
#Override
public void init() {
iceCream = new IceCream(160, GameMainActivity.GAME_HEIGHT - 45
- IC3_HEIGHT, ICECREAM_WIDTH, IC3_HEIGHT);
fire = new Fire(10, 10, FIRE_WIDTH, FIRE_HEIGHT);
//cloud = new Cloud(100, 100);
// cloud2 = new Cloud(500, 50);
iceCream2 = true;
// iceCream2 = false;
// iceCream1 = false;
}
#Override
public void update(float delta) {
fire.update(delta, fireSpeed);
iceCream.update(delta);
if (!iceCream.isFrozen()) {
setCurrentState(new GameOverState(playerScore / 100));
}
}
#Override
public void render(Painter g) {
g.setColor(Color.rgb(208, 244, 247));
g.fillRect(0, 0, GameMainActivity.GAME_WIDTH,
GameMainActivity.GAME_HEIGHT);
renderSun(g);
renderClouds(g);
g.drawImage(Assets.grass, 0, 405);
renderIceCream(g);
renderFire(g);
renderScore(g);
}
private void renderScore(Painter g) {
g.setFont(Typeface.SANS_SERIF, 25);
g.setColor(Color.GRAY);
g.drawString("" + playerScore / 100, 20, 30);
}
private void renderFire(Painter g) {
g.drawImage(Assets.gameTestFire, (int) fire.getX(), (int) fire.getY(), FIRE_WIDTH, FIRE_HEIGHT);
if(Rect.intersects(iceCream.getRect(),fire.getRect())){
fire.reset();
}
}
private void renderIceCream(Painter g) {
if (iceCream3) {
g.drawImage(Assets.iceCream3, (int) iceCream.getX(), (int) iceCream.getY(), ICECREAM_WIDTH, IC3_HEIGHT);
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream3 = false;
iceCream2 = true;
}
}
if (iceCream2) {
g.drawImage(Assets.iceCream2, (int) iceCream.getX(), (int) iceCream.getY() + 25, ICECREAM_WIDTH, IC2_HEIGHT);
//
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream2 = false;
iceCream1 = true;
}
}
if (iceCream1) {
g.drawImage(Assets.iceCream1, (int) iceCream.getX(), (int) iceCream.getY() + 50, ICECREAM_WIDTH, IC1_HEIGHT);
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream1 = false;
iceCream.melted();
}
}
}
private void renderSun(Painter g) {
g.setColor(Color.rgb(255, 165, 0));
g.fillOval(715, -85, 170, 170);
g.setColor(Color.YELLOW);
g.fillOval(725, -75, 150, 150);
}
private void renderClouds(Painter g) {
g.drawImage(Assets.cloud1, cloudX, cloudY, 100, 60);
cloudX += 4;
if (cloudX > 800) {
cloudX = 0;
}
}
#Override
public boolean onTouch(MotionEvent e, int scaledX, int scaledY) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
recentTouchY = scaledY;
} else if (e.getAction() == MotionEvent.ACTION_UP) {
if (scaledY - recentTouchY < -50) {
iceCream.jump();
} else if (scaledY - recentTouchY > 50) {
}
}
return true;
}
}
This is the IceCream class
package rect.draw.gametest.model;
import android.graphics.Rect;
public class IceCream {
private static final float ACCEL_GRAVITY = 1800 ;
private static final int JUMP_VELOCITY =-600 ;
private float x,y;
private int width,height;
private Rect rect,ground;
public boolean isFrozen,durationEnded,isGrounded;
private int velY;
public IceCream(float x, float y, int width, int height){
this.x=x;
this.y=y;
this.width=width;
this.height=height;
rect = new Rect((int) x, (int) y, (int) x + width, (int) y + height);
this.x = x;
this.y = y;
this.width = width;
this.height = height;
ground = new Rect(0, 405, 0 + 800, 405 + 45);
rect = new Rect();
isFrozen = true;
}
public void update(float delta) {
if (!isGrounded()) {
velY += ACCEL_GRAVITY * delta;
} else {
y = 406 - height;
velY = 0;
}
y += velY * delta;
updateRect();
}
public void jump(){
y -= 10;
velY = JUMP_VELOCITY;
updateRect();
}
public boolean isFrozen(){
return isFrozen;
}
public void melted(){
isFrozen = false;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public void updateRect() {
rect.set((int) x, (int) y, (int) x + width, (int) y + height);
}
public Rect getRect(){
return rect;
}
public boolean isGrounded() {
return Rect.intersects(rect, ground);
}
}

I think the problem can be solved by adding these two else statements:
private void renderIceCream(Painter g) {
if (iceCream3) {
...
}
else if (iceCream2) {
...
}
else if (iceCream1) {
...
}
}
Without the else statements, when iceCream3 is true and there is a collision, iceCream2 becomes true and Java steps into the next if statement where iceCream1 becomes true. With the else statements, this does not happen. If you move away the fire afterwards by calling fire.reset(), your code should work now.

Related

Exit to a different Activity when game loop ends?

I want my game to exit and go to a separate Activity when the user collides. For example, I want it to go back to my main menu. I've tried adding a Button, new intent method etc and these don't work. I can't find the answer anywhere and i'm not knowledgeable enough to do this as I'm learning. I've trawled the internet but nothing has really helped. Any advice would be awesome. My idea was to change the newgame() method to exit the game?
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;
import java.util.Random;
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
private Threading threading;
private BackgroundImage bg;
public static final int WIDTH = 856;
public static final int HEIGHT = 480;
public static final int MovementSpeed = -8;
private Player player;
private ArrayList<BorderTop> borderTop;
private ArrayList<BorderBottom> borderBottom;
private ArrayList<Smokepuff> smoke;
private ArrayList<Missile> missiles;
private int MaximumBorderHeight;
private int MinimumBorderHeight;
private boolean topDown = true;
private boolean botDown = true;
private int progressDifficulty = 20;
private Random rand = new Random();
private boolean newGameCreated;
private long smokeStartTime;
private long missileStartTime;
public GamePanel(Context context) {
super(context);
getHolder().addCallback(this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
bg = new BackgroundImage(BitmapFactory.decodeResource(getResources(), R.drawable.grassbg1));
player = new Player(BitmapFactory.decodeResource(getResources(), R.drawable.smallcatfinal), 40, 44, 1);
borderTop = new ArrayList<BorderTop>();
borderBottom = new ArrayList<BorderBottom>();
smoke = new ArrayList<Smokepuff>();
missiles = new ArrayList<Missile>();
smokeStartTime= System.nanoTime();
missileStartTime = System.nanoTime();
threading = new Threading(getHolder(), this);
threading.setRunning(true);
threading.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
int counter = 0;
while (retry && counter < 1000) {
counter++;
try {
threading.setRunning(false);
threading.join();
retry = false;
threading = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!player.getPlaying()) {
player.setPlaying(true);
player.setUp(true);
}else{
player.setUp(true);
}
return true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
player.setUp(false);
return true;
}
return super.onTouchEvent(event);
}
public void update() {
if (player.getPlaying()) {
bg.update();
player.update();
MaximumBorderHeight = 30 + player.getScore() / progressDifficulty;
if (MaximumBorderHeight > HEIGHT / 4) MaximumBorderHeight = HEIGHT / 4;
MinimumBorderHeight = 5 + player.getScore() / progressDifficulty;
//check bottom border collision
for (int i = 0; i < borderBottom.size(); i++) {
if (collision(borderBottom.get(i), player))
player.setPlaying(false);
}
//check top border collision
for (int i = 0; i < borderTop.size(); i++) {
if (collision(borderTop.get(i), player))
player.setPlaying(false);
}
this.updateTop();
this.updateBottom();
long missileElapsed = (System.nanoTime() - missileStartTime) / 1000000;
if (missileElapsed > (2000 - player.getScore() / 4)) {
//first missile always goes down the middle
if (missiles.size() == 0) {
missiles.add(new Missile(BitmapFactory.decodeResource(getResources(), R.drawable.
missile), WIDTH + 10, HEIGHT / 2, 45, 15, player.getScore(), 13));
} else {
missiles.add(new Missile(BitmapFactory.decodeResource(getResources(), R.drawable.missile),
WIDTH + 10, (int) (rand.nextDouble() * (HEIGHT - (MaximumBorderHeight * 2)) + MaximumBorderHeight), 45, 15, player.getScore(), 13));
}
//reset timer
missileStartTime = System.nanoTime();
}
//loop through every missile and check collision and remove
for (int i = 0; i < missiles.size(); i++) {
//update missile
missiles.get(i).update();
if (collision(missiles.get(i), player)) {
missiles.remove(i);
player.setPlaying(false);
break;
}
//remove missile if it is way off the screen
if (missiles.get(i).getX() < -100) {
missiles.remove(i);
break;
}
}
long elapsed = (System.nanoTime() - smokeStartTime) / 1000000;
if (elapsed > 120) {
smoke.add(new Smokepuff(player.getX(), player.getY() + 10));
smokeStartTime = System.nanoTime();
}
for (int i = 0; i < smoke.size(); i++) {
smoke.get(i).update();
if (smoke.get(i).getX() < -10) {
smoke.remove(i);
}
}
} else {
newGameCreated = false;
if (!newGameCreated) {
newGame();
}
}
public boolean collision (GameObject a, GameObject b)
{
if (Rect.intersects(a.getRectangle(), b.getRectangle())) {
return true;
}
return false;
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
final float ScaleX = (float) getWidth() / WIDTH*1.f;
final float ScaleY = (float) getHeight() / HEIGHT*1.f;
if (canvas != null) {
final int savedState = canvas.save();
canvas.scale(ScaleX, ScaleY);
bg.draw(canvas);
player.draw(canvas);
for(Smokepuff sp: smoke)
{
sp.draw(canvas);
}
//draw missiles
for(Missile m: missiles)
{
m.draw(canvas);
}
for(BorderTop bt: borderTop)
{
bt.draw(canvas);
}
for(BorderBottom bb: borderBottom)
{
bb.draw(canvas);
}
canvas.restoreToCount(savedState);
}
}
public void updateBottom() {
if (player.getScore() % 40 == 0) {
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(), R.drawable.brick),
borderBottom.get(borderBottom.size() - 1).getX() + 20, (int) ((rand.nextDouble()
* MaximumBorderHeight) + (HEIGHT - MaximumBorderHeight))));
}
//update bottom border
for (int i = 0; i < borderBottom.size(); i++) {
borderBottom.get(i).update();
//if border is moving off screen, remove it and add a corresponding new one
if (borderBottom.get(i).getX() < -20) {
borderBottom.remove(i);
//determine if border will be moving up or down
if (borderBottom.get(borderBottom.size() - 1).getY() <= HEIGHT - MaximumBorderHeight) {
botDown = true;
}
if (borderBottom.get(borderBottom.size() - 1).getY() >= HEIGHT - MinimumBorderHeight) {
botDown = false;
}
if (botDown) {
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(),R.drawable.brick
), borderBottom.get(borderBottom.size() - 1).getX() + 20, borderBottom.get(borderBottom.size() - 1
).getY() + 1));
} else {
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(), R.drawable.brick
), borderBottom.get(borderBottom.size() - 1).getX() + 20, borderBottom.get(borderBottom.size() - 1
).getY() - 1));
}
}
}
}
public void updateTop()
{
if (player.getScore() % 50 == 0) {
borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(), R.drawable.brick), borderTop.get(borderTop.size() - 1).getX() + 20, 0, (int) ((rand.nextDouble() * (MaximumBorderHeight)) + 1)));
}
for (int i = 0; i < borderTop.size(); i++) {
borderTop.get(i).update();
if (borderTop.get(i).getX() < -20) {
borderTop.remove(i);
if (borderTop.get(borderTop.size() - 1).getHeight() >= MaximumBorderHeight) {
topDown = false;
}
if (borderTop.get(borderTop.size() - 1).getHeight() <= MinimumBorderHeight) {
topDown = true;
}
if (topDown) {
borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(), R.drawable.brick), borderTop.get(borderTop.size() - 1).getX() + 20, 0, borderTop.get(borderTop.size() - 1).getHeight() + 1));
} else {
borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(), R.drawable.brick), borderTop.get(borderTop.size() - 1).getX() + 20, 0, borderTop.get(borderTop.size() - 1).getHeight() - 1));
}
}
}
}
public void newGame() {
borderBottom.clear();
borderTop.clear();
missiles.clear();
smoke.clear();
MinimumBorderHeight = 5;
MaximumBorderHeight = 30;
player.resetDY();
player.resetScore();
player.setY(HEIGHT/2);
//create initial borders
//initial top border
for(int i = 0; i*20<WIDTH+40;i++)
{
// first top border create
if(i==0)
{borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(),R.drawable.brick
),i*20,0, 10));
}
else
{
borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(),R.drawable.brick
),i*20,0, borderTop.get(i-1).getHeight()+1));
}
}
//initial bottom border
for(int i = 0; i*20<WIDTH+40; i++)
{
//first border ever created
if(i==0)
{
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(),R.drawable.brick)
,i*20,HEIGHT - MinimumBorderHeight));
}
//adding borders until the initial screen is filed
else
{
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(), R.drawable.brick),
i * 20, borderBottom.get(i - 1).getY() - 1));
}
}
newGameCreated = true;
}
}

Boundary box not updating correctly

As an intro, my app is a flappy bird style game. You have fire at the bottom and top of the screen, You have to jump at the right time in order not to get hit. You have 3 different ice cream cones. Each a different height. Whenever the icecream collides with the fire, it goes down in height.
The issue I am having is whenever the icecream reduces in height, the boundary box seems to not get updated, even though I assumed that my updateRect() logic is correct.
In regards to the top boundary of the icecream and the bottom boundary of the fire, The icecreams with the smaller heights appear as they are suppose to visually on the screen, but their bounding box seems to match that of the tallest icecreams.
I noticed this because it seems as if I can get pretty close to the fires at the top without colliding when I'm using the tallest icecream. But when I use the shorter icecreams, I can still collide even though the gap seems bigger than compared to the tallest.
These are the codes I believe to be relevant to this issue
private InfJIceCream iceCream;
private ArrayList<Fire> lowFires;
private ArrayList<Fire> highFires;
private static int IC1_HEIGHT = 77;
private static int IC2_HEIGHT= 102;
private static int IC3_HEIGHT = 127;
private static int FIRE_WIDTH = 60;
private static int FIRE_HEIGHT = 60;
#Override
public void init() {
/* In order to align the icecream properly on the y-axis, I replaced 45(The height of the ground) with 44 because
* when 45 is part of the equation, it seems as if the iceCreams drops for a bit when initialized
* or does some sort of funny business
*
* This detail is virtually irrelevant but I feel as if 44 does a better job in making sure
* the iceCream is on the ground at the beginning of the gameplay
*/
//InfJIceCream(x,y,width,height);
iceCream = new InfJIceCream(160, GameMainActivity.GAME_HEIGHT - 44
- IC3_HEIGHT, ICECREAM_WIDTH, IC3_HEIGHT);
lowFires = new ArrayList<Fire>();
highFires = new ArrayList<Fire>();
for (int i = 0; i < 5; i++) {
Fire lowFire = new Fire(i * 200, Fire.LOWER_Y, FIRE_WIDTH, FIRE_HEIGHT);
Fire highFire = new Fire(i * 300, Fire.UPPER_Y, FIRE_WIDTH, FIRE_HEIGHT);
lowFires.add(i, lowFire);
highFires.add(i, highFire);
}
iceCream3 = true;
}
private void renderFire(Painter g) {
for (Fire fire : lowFires) {
if (fire.isVisible()) {
g.drawImage(Assets.fire, (int) fire.getX(), (int) fire.getY(), FIRE_WIDTH, FIRE_HEIGHT);
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
fire.resetLow();
}
}
}
for (Fire fire : highFires) {
if (fire.isVisible()) {
g.drawImage(Assets.fire, (int) fire.getX(), (int) fire.getY(), FIRE_WIDTH, FIRE_HEIGHT);
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
fire.resetHigh();
}
}
}
}
private void renderIceCream(Painter g) {
/*
iceCream3 is true by default
*/
//Checking for collisions with the fire on the ground
for (Fire fire : lowFires){
if (iceCream3) {
g.drawImage(Assets.iceCream3, (int) iceCream.getX(), (int) iceCream.getY(), ICECREAM_WIDTH, IC3_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream3 = false;
iceCream2 = true;
}
} else if (iceCream2) {
g.drawImage(Assets.iceCream2, (int) iceCream.getX(), (int) iceCream.getY() + 25, ICECREAM_WIDTH, IC2_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream2 = false;
iceCream1 = true;
}
} else if (iceCream1) {
g.drawImage(Assets.iceCream1, (int) iceCream.getX(), (int) iceCream.getY() + 50, ICECREAM_WIDTH, IC1_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
setCurrentState(new GameOverState(playerScore/100));
}
}}
// Checking for collisions with the fire above gounnd.
for (Fire fire : highFires){
if (iceCream3) {
g.drawImage(Assets.iceCream3, (int) iceCream.getX(), (int) iceCream.getY(), ICECREAM_WIDTH, IC3_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream3 = false;
iceCream2 = true;
}
} else if (iceCream2) {
g.drawImage(Assets.iceCream2, (int) iceCream.getX(), (int) iceCream.getY() + 25, ICECREAM_WIDTH, IC2_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream2 = false;
iceCream1 = true;
}
} else if (iceCream1) {
g.drawImage(Assets.iceCream1, (int) iceCream.getX(), (int) iceCream.getY() + 50, ICECREAM_WIDTH, IC1_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
setCurrentState(new GameOverState(playerScore/100));
}
}}
}
This is the Whole class.
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.view.MotionEvent;
import java.util.ArrayList;
import rect.draw.gametest.Assets;
import rect.draw.gametest.GameMainActivity;
import rect.draw.gametest.model.Fire;
import rect.draw.gametest.model.InfJIceCream;
import rect.draw.gametest.model.util.Painter;
public class HardState extends State {
private InfJIceCream iceCream;
private ArrayList<Fire> lowFires;
private ArrayList<Fire> highFires;
private int cloudX = 0;
private int cloudY = 100;
private int playerScore = 1;
private int fireSpeed = -200;
private static int ICECREAM_WIDTH = 38;
private static int IC1_HEIGHT = 77;
private static int IC2_HEIGHT= 102;
private static int IC3_HEIGHT = 127;
private static int FIRE_WIDTH = 60;
private static int FIRE_HEIGHT = 60;
public boolean iceCream1,iceCream2,iceCream3;
private float recentTouchY;
#Override
public void init() {
/* In order to align the icecream properly on the y-axis, I replaced 45(The height of the ground) with 44 because
* when 45 is part of the equation, it seems as if the iceCreams drops for a bit when initialized
* or does some sort of funny business
*
* This detail is virtually irrelevant but I feel as if 44 does a better job in making sure
* the iceCream is on the ground at the beginning of the gameplay
*/
iceCream = new InfJIceCream(160, GameMainActivity.GAME_HEIGHT - 44
- IC3_HEIGHT, ICECREAM_WIDTH, IC3_HEIGHT);
lowFires = new ArrayList<Fire>();
highFires = new ArrayList<Fire>();
for (int i = 0; i < 5; i++) {
// The y position initialization for the fires are irrelevant because they are invisible
// until the resetLow() method is called. Which will then change the y position
Fire lowFire = new Fire(i * 200, Fire.LOWER_Y, FIRE_WIDTH, FIRE_HEIGHT);
Fire highFire = new Fire(i * 300, Fire.UPPER_Y, FIRE_WIDTH, FIRE_HEIGHT);
lowFires.add(i, lowFire);
highFires.add(i, highFire);
}
iceCream3 = true;
}
#Override
public void update(float delta) {
for(Fire fire: lowFires){
fire.update(delta, fireSpeed);
}
for(Fire fire: highFires){
fire.update(delta,fireSpeed);
}
playerScore += 1;
iceCream.update(delta);
}
#Override
public void render(Painter g) {
g.setColor(Color.rgb(30, 144, 255));
g.fillRect(0, 0, GameMainActivity.GAME_WIDTH,
GameMainActivity.GAME_HEIGHT);
renderSun(g);
renderClouds(g);
g.drawImage(Assets.mountains, 0, 81);
g.drawImage(Assets.grass, 0, 405);
g.setColor(Color.BLACK);
renderSwipeUp(g);
renderFire(g);
renderScore(g);
renderIceCream(g);
}
private void renderSwipeUp(Painter g){
for(Fire fire : lowFires) {
if (!fire.isVisible()) {
g.drawImage(Assets.swipeUp, 200, 15, 200, 230);
}
// All fires in the Array have to return isVisible = true before the swipeUp image goes away
}
}
private void renderScore(Painter g) {
g.setFont(Typeface.SANS_SERIF, 25);
g.setColor(Color.BLACK);
g.drawString("" + playerScore / 100, 20, 30);
}
private void renderFire(Painter g) {
for (Fire fire : lowFires) {
if (fire.isVisible()) {
g.drawImage(Assets.fire, (int) fire.getX(), (int) fire.getY(), FIRE_WIDTH, FIRE_HEIGHT);
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
fire.resetLow();
}
}
}
for (Fire fire : highFires) {
if (fire.isVisible()) {
g.drawImage(Assets.fire, (int) fire.getX(), (int) fire.getY(), FIRE_WIDTH, FIRE_HEIGHT);
if (Rect.intersects(iceCream.getRect(), fire.getRect())) {
fire.resetHigh();
}
}
}
}
private void renderIceCream(Painter g) {
/*
iceCream3 is true by default
*/
//Checking for collisions with the fire on the ground
for (Fire fire : lowFires){
if (iceCream3) {
g.drawImage(Assets.iceCream3, (int) iceCream.getX(), (int) iceCream.getY(), ICECREAM_WIDTH, IC3_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream3 = false;
iceCream2 = true;
}
} else if (iceCream2) {
g.drawImage(Assets.iceCream2, (int) iceCream.getX(), (int) iceCream.getY() + 25, ICECREAM_WIDTH, IC2_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream2 = false;
iceCream1 = true;
}
} else if (iceCream1) {
g.drawImage(Assets.iceCream1, (int) iceCream.getX(), (int) iceCream.getY() + 50, ICECREAM_WIDTH, IC1_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
setCurrentState(new GameOverState(playerScore/100));
}
}}
// Checking for collisions with the fire above gounnd.
for (Fire fire : highFires){
if (iceCream3) {
g.drawImage(Assets.iceCream3, (int) iceCream.getX(), (int) iceCream.getY(), ICECREAM_WIDTH, IC3_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream3 = false;
iceCream2 = true;
}
} else if (iceCream2) {
g.drawImage(Assets.iceCream2, (int) iceCream.getX(), (int) iceCream.getY() + 25, ICECREAM_WIDTH, IC2_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
iceCream2 = false;
iceCream1 = true;
}
} else if (iceCream1) {
g.drawImage(Assets.iceCream1, (int) iceCream.getX(), (int) iceCream.getY() + 50, ICECREAM_WIDTH, IC1_HEIGHT);
if (fire.isVisible() && Rect.intersects(iceCream.getRect(), fire.getRect())) {
setCurrentState(new GameOverState(playerScore/100));
}
}}
}
private void renderSun(Painter g) {
g.setColor(Color.rgb(255, 165, 0));
g.fillOval(715, -85, 170, 170);
g.setColor(Color.YELLOW);
g.fillOval(725, -75, 150, 150);
}
private void renderClouds(Painter g) {
g.drawImage(Assets.cloud1, cloudX, cloudY, 100, 60);
cloudX += 4;
if (cloudX > 950) {
cloudX = -100;
}
}
#Override
public boolean onTouch(MotionEvent e, int scaledX, int scaledY) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
recentTouchY = scaledY;
} else if (e.getAction() == MotionEvent.ACTION_UP) {
if (scaledY - recentTouchY < -50) {
iceCream.jump();
} else if (scaledY - recentTouchY > 50) {
}
}
return true;
}
}

Folding animation in Both Horizontal / Vertical direction for multiple Images using ImageView

I want make fold animation in both horizontal & vertical and i followed the below link for (DevBytes) for making folding animation.However this works for only for single image. How to make it to work for multiple Image Folding one by one (By swiping and autoplay)
Folding Layout class:
public class FoldingLayout extends ViewGroup {
public static enum Orientation {
VERTICAL,
HORIZONTAL
}
private final String FOLDING_VIEW_EXCEPTION_MESSAGE = "Folding Layout can only 1 child at " +
"most";
private final float SHADING_ALPHA = 0.8f;
private final float SHADING_FACTOR = 0.5f;
private final int DEPTH_CONSTANT = 1500;
private final int NUM_OF_POLY_POINTS = 8;
private Rect[] mFoldRectArray;
private Matrix [] mMatrix;
private Orientation mOrientation = Orientation.HORIZONTAL;
private float mAnchorFactor = 0;
private float mFoldFactor = 0;
private int mNumberOfFolds = 2;
private boolean mIsHorizontal = true;
private int mOriginalWidth = 0;
private int mOriginalHeight = 0;
private float mFoldMaxWidth = 0;
private float mFoldMaxHeight = 0;
private float mFoldDrawWidth = 0;
private float mFoldDrawHeight = 0;
private boolean mIsFoldPrepared = false;
private boolean mShouldDraw = true;
private Paint mSolidShadow;
private Paint mGradientShadow;
private LinearGradient mShadowLinearGradient;
private Matrix mShadowGradientMatrix;
private float [] mSrc;
private float [] mDst;
private OnFoldListener mFoldListener;
private float mPreviousFoldFactor = 0;
private Bitmap mFullBitmap;
private Rect mDstRect;
public FoldingLayout(Context context) {
super(context);
}
public FoldingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FoldingLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected boolean addViewInLayout(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
throwCustomException(getChildCount());
boolean returnValue = super.addViewInLayout(child, index, params, preventRequestLayout);
return returnValue;
}
#Override
public void addView(View child, int index, LayoutParams params) {
throwCustomException(getChildCount());
super.addView(child, index, params);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
View child = getChildAt(0);
measureChild(child,widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
View child = getChildAt(0);
child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
updateFold();
}
private class NumberOfFoldingLayoutChildrenException extends RuntimeException {
public NumberOfFoldingLayoutChildrenException(String message) {
super(message);
}
}
private void throwCustomException (int numOfChildViews) {
if (numOfChildViews == 1) {
throw new NumberOfFoldingLayoutChildrenException(FOLDING_VIEW_EXCEPTION_MESSAGE);
}
}
public void setFoldListener(OnFoldListener foldListener) {
mFoldListener = foldListener;
}
public void setFoldFactor(float foldFactor) {
if (foldFactor != mFoldFactor) {
mFoldFactor = foldFactor;
calculateMatrices();
invalidate();
}
}
public void setOrientation(Orientation orientation) {
if (orientation != mOrientation) {
mOrientation = orientation;
updateFold();
}
}
public void setAnchorFactor(float anchorFactor) {
if (anchorFactor != mAnchorFactor) {
mAnchorFactor = anchorFactor;
updateFold();
}
}
public void setNumberOfFolds(int numberOfFolds) {
if (numberOfFolds != mNumberOfFolds) {
mNumberOfFolds = numberOfFolds;
updateFold();
}
}
public float getAnchorFactor() {
return mAnchorFactor;
}
public Orientation getOrientation() {
return mOrientation;
}
public float getFoldFactor() {
return mFoldFactor;
}
public int getNumberOfFolds() {
return mNumberOfFolds;
}
private void updateFold() {
prepareFold(mOrientation, mAnchorFactor, mNumberOfFolds);
calculateMatrices();
invalidate();
}
private void prepareFold(Orientation orientation, float anchorFactor, int numberOfFolds) {
mSrc = new float[NUM_OF_POLY_POINTS];
mDst = new float[NUM_OF_POLY_POINTS];
mDstRect = new Rect();
mFoldFactor = 0;
mPreviousFoldFactor = 0;
mIsFoldPrepared = false;
mSolidShadow = new Paint();
mGradientShadow = new Paint();
mOrientation = orientation;
mIsHorizontal = (orientation == Orientation.HORIZONTAL);
if (mIsHorizontal) {
mShadowLinearGradient = new LinearGradient(0, 0, SHADING_FACTOR, 0, Color.BLACK,
Color.TRANSPARENT, TileMode.CLAMP);
} else {
mShadowLinearGradient = new LinearGradient(0, 0, 0, SHADING_FACTOR, Color.BLACK,
Color.TRANSPARENT, TileMode.CLAMP);
}
mGradientShadow.setStyle(Style.FILL);
mGradientShadow.setShader(mShadowLinearGradient);
mShadowGradientMatrix = new Matrix();
mAnchorFactor = anchorFactor;
mNumberOfFolds = numberOfFolds;
mOriginalWidth = getMeasuredWidth();
mOriginalHeight = getMeasuredHeight();
mFoldRectArray = new Rect[mNumberOfFolds];
mMatrix = new Matrix [mNumberOfFolds];
for (int x = 0; x < mNumberOfFolds; x++) {
mMatrix[x] = new Matrix();
}
int h = mOriginalHeight;
int w = mOriginalWidth;
if (FoldingLayoutActivity.IS_JBMR2) {
mFullBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mFullBitmap);
getChildAt(0).draw(canvas);
}
int delta = Math.round(mIsHorizontal ? ((float) w) / ((float) mNumberOfFolds) :
((float) h) /((float) mNumberOfFolds));
for (int x = 0; x < mNumberOfFolds; x++) {
if (mIsHorizontal) {
int deltap = (x + 1) * delta > w ? w - x * delta : delta;
mFoldRectArray[x] = new Rect(x * delta, 0, x * delta + deltap, h);
} else {
int deltap = (x + 1) * delta > h ? h - x * delta : delta;
mFoldRectArray[x] = new Rect(0, x * delta, w, x * delta + deltap);
}
}
if (mIsHorizontal) {
mFoldMaxHeight = h;
mFoldMaxWidth = delta;
} else {
mFoldMaxHeight = delta;
mFoldMaxWidth = w;
}
mIsFoldPrepared = true;
}
private void calculateMatrices() {
mShouldDraw = true;
if (!mIsFoldPrepared) {
return;
}
if (mFoldFactor == 1) {
mShouldDraw = false;
return;
}
if (mFoldFactor == 0 && mPreviousFoldFactor > 0) {
mFoldListener.onEndFold();
}
if (mPreviousFoldFactor == 0 && mFoldFactor > 0) {
mFoldListener.onStartFold();
}
mPreviousFoldFactor = mFoldFactor;
for (int x = 0; x < mNumberOfFolds; x++) {
mMatrix[x].reset();
}
float cTranslationFactor = 1 - mFoldFactor;
float translatedDistance = mIsHorizontal ? mOriginalWidth * cTranslationFactor :
mOriginalHeight * cTranslationFactor;
float translatedDistancePerFold = Math.round(translatedDistance / mNumberOfFolds);
mFoldDrawWidth = mFoldMaxWidth < translatedDistancePerFold ?
translatedDistancePerFold : mFoldMaxWidth;
mFoldDrawHeight = mFoldMaxHeight < translatedDistancePerFold ?
translatedDistancePerFold : mFoldMaxHeight;
float translatedDistanceFoldSquared = translatedDistancePerFold * translatedDistancePerFold;
float depth = mIsHorizontal ?
(float)Math.sqrt((double)(mFoldDrawWidth * mFoldDrawWidth -
translatedDistanceFoldSquared)) :
(float)Math.sqrt((double)(mFoldDrawHeight * mFoldDrawHeight -
translatedDistanceFoldSquared));
float scaleFactor = DEPTH_CONSTANT / (DEPTH_CONSTANT + depth);
float scaledWidth, scaledHeight, bottomScaledPoint, topScaledPoint, rightScaledPoint,
leftScaledPoint;
if (mIsHorizontal) {
scaledWidth = mFoldDrawWidth * cTranslationFactor;
scaledHeight = mFoldDrawHeight * scaleFactor;
} else {
scaledWidth = mFoldDrawWidth * scaleFactor;
scaledHeight = mFoldDrawHeight * cTranslationFactor;
}
topScaledPoint = (mFoldDrawHeight - scaledHeight) / 2.0f;
bottomScaledPoint = topScaledPoint + scaledHeight;
leftScaledPoint = (mFoldDrawWidth - scaledWidth) / 2.0f;
rightScaledPoint = leftScaledPoint + scaledWidth;
float anchorPoint = mIsHorizontal ? mAnchorFactor * mOriginalWidth :
mAnchorFactor * mOriginalHeight;
/* The fold along which the anchor point is located. */
float midFold = mIsHorizontal ? (anchorPoint / mFoldDrawWidth) : anchorPoint /
mFoldDrawHeight;
mSrc[0] = 0;
mSrc[1] = 0;
mSrc[2] = 0;
mSrc[3] = mFoldDrawHeight;
mSrc[4] = mFoldDrawWidth;
mSrc[5] = 0;
mSrc[6] = mFoldDrawWidth;
mSrc[7] = mFoldDrawHeight;
for (int x = 0; x < mNumberOfFolds; x++) {
boolean isEven = (x % 2 == 0);
if (mIsHorizontal) {
mDst[0] = (anchorPoint > x * mFoldDrawWidth) ? anchorPoint + (x - midFold) *
scaledWidth : anchorPoint - (midFold - x) * scaledWidth;
mDst[1] = isEven ? 0 : topScaledPoint;
mDst[2] = mDst[0];
mDst[3] = isEven ? mFoldDrawHeight: bottomScaledPoint;
mDst[4] = (anchorPoint > (x + 1) * mFoldDrawWidth) ? anchorPoint + (x + 1 - midFold)
* scaledWidth : anchorPoint - (midFold - x - 1) * scaledWidth;
mDst[5] = isEven ? topScaledPoint : 0;
mDst[6] = mDst[4];
mDst[7] = isEven ? bottomScaledPoint : mFoldDrawHeight;
} else {
mDst[0] = isEven ? 0 : leftScaledPoint;
mDst[1] = (anchorPoint > x * mFoldDrawHeight) ? anchorPoint + (x - midFold) *
scaledHeight : anchorPoint - (midFold - x) * scaledHeight;
mDst[2] = isEven ? leftScaledPoint: 0;
mDst[3] = (anchorPoint > (x + 1) * mFoldDrawHeight) ? anchorPoint + (x + 1 -
midFold) * scaledHeight : anchorPoint - (midFold - x - 1) * scaledHeight;
mDst[4] = isEven ? mFoldDrawWidth : rightScaledPoint;
mDst[5] = mDst[1];
mDst[6] = isEven ? rightScaledPoint : mFoldDrawWidth;
mDst[7] = mDst[3];
}
for (int y = 0; y < 8; y ++) {
mDst[y] = Math.round(mDst[y]);
}
int alpha = (int) (mFoldFactor * 255 * SHADING_ALPHA);
mSolidShadow.setColor(Color.argb(alpha, 0, 0, 0));
if (mIsHorizontal) {
mShadowGradientMatrix.setScale(mFoldDrawWidth, 1);
mShadowLinearGradient.setLocalMatrix(mShadowGradientMatrix);
} else {
mShadowGradientMatrix.setScale(1, mFoldDrawHeight);
mShadowLinearGradient.setLocalMatrix(mShadowGradientMatrix);
}
mGradientShadow.setShader(mShadowLinearGradient);
mGradientShadow.setAlpha(alpha);
}
#Override
protected void dispatchDraw(Canvas canvas) {
if (!mIsFoldPrepared || mFoldFactor == 0) {
super.dispatchDraw(canvas);
return;
}
if (!mShouldDraw) {
return;
}
for (int x = 0; x < mNumberOfFolds; x++) {
src = mFoldRectArray[x];
canvas.concat(mMatrix[x]);
if (FoldingLayoutActivity.IS_JBMR2) {
mDstRect.set(0, 0, src.width(), src.height());
canvas.drawBitmap(mFullBitmap, src, mDstRect, null);
} else {
canvas.clipRect(0, 0, src.right - src.left, src.bottom - src.top);
if (mIsHorizontal) {
canvas.translate(-src.left, 0);
} else {
canvas.translate(0, -src.top);
}
super.dispatchDraw(canvas);
if (mIsHorizontal) {
canvas.translate(src.left, 0);
} else {
canvas.translate(0, src.top);
}
}
if (x % 2 == 0) {
canvas.drawRect(0, 0, mFoldDrawWidth, mFoldDrawHeight, mSolidShadow);
} else {
canvas.drawRect(0, 0, mFoldDrawWidth, mFoldDrawHeight, mGradientShadow);
}
canvas.restore();
}
}
}
// onFoldListener
public interface OnFoldListener {
public void onStartFold();
public void onEndFold();
}
// FoldingLayoutActivity
public class FoldingLayoutActivity extends Activity {
private final int ANTIALIAS_PADDING = 1;
private final int FOLD_ANIMATION_DURATION = 1000;
static final boolean IS_JBMR2 = Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR2;
private FoldingLayout mFoldLayout;
private SeekBar mAnchorSeekBar;
private Orientation mOrientation = Orientation.HORIZONTAL;
private int mTranslation = 0;
private int mNumberOfFolds = 2;
private int mParentPositionY = -1;
private int mTouchSlop = -1;
private float mAnchorFactor = 0;
private boolean mDidLoadSpinner = true;
private boolean mDidNotStartScroll = true;
private boolean mIsCameraFeed = false;
private boolean mIsSepiaOn = true;
private GestureDetector mScrollGestureDetector;
private ItemSelectedListener mItemSelectedListener;
private Camera mCamera;
private TextureView mTextureView;
private ImageView mImageView;
private Paint mSepiaPaint;
private Paint mDefaultPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fold);
mImageView = (ImageView)findViewById(R.id.image_view);
mImageView.setPadding(ANTIALIAS_PADDING, ANTIALIAS_PADDING, ANTIALIAS_PADDING,
ANTIALIAS_PADDING);
mImageView.setScaleType(ImageView.ScaleType.FIT_XY);
mImageView.setImageDrawable(getResources().getDrawable(R.drawable.image));
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
mAnchorSeekBar = (SeekBar)findViewById(R.id.anchor_seek_bar);
mFoldLayout = (FoldingLayout)findViewById(R.id.fold_view);
mFoldLayout.setBackgroundColor(Color.BLACK);
mFoldLayout.setFoldListener(mOnFoldListener);
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
mAnchorSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);
mScrollGestureDetector = new GestureDetector(this, new ScrollGestureDetector());
mItemSelectedListener = new ItemSelectedListener();
mDefaultPaint = new Paint();
mSepiaPaint = new Paint();
ColorMatrix m1 = new ColorMatrix();
ColorMatrix m2 = new ColorMatrix();
m1.setSaturation(0);
m2.setScale(1f, .95f, .82f, 1.0f);
m1.setConcat(m2, m1);
mSepiaPaint.setColorFilter(new ColorMatrixColorFilter(m1));
}
private OnFoldListener mOnFoldListener =
new OnFoldListener() {
#Override
public void onStartFold() {
if (mIsSepiaOn) {
setSepiaLayer(mFoldLayout.getChildAt(0), true);
}
}
#Override
public void onEndFold() {
setSepiaLayer(mFoldLayout.getChildAt(0), false);
}
};
private void setSepiaLayer (View view, boolean isSepiaLayerOn) {
if (!IS_JBMR2) {
if (isSepiaLayerOn) {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
view.setLayerPaint(mSepiaPaint);
} else {
view.setLayerPaint(mDefaultPaint);
}
}
}
private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView
.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
mCamera = Camera.open();
if (mCamera == null && Camera.getNumberOfCameras() > 1) {
mCamera = mCamera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
}
if (mCamera == null) {
return;
}
try {
mCamera.setPreviewTexture(surfaceTexture);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar
.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
mTranslation = 0;
mAnchorFactor = ((float)mAnchorSeekBar.getProgress())/100.0f;
mFoldLayout.setAnchorFactor(mAnchorFactor);
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (IS_JBMR2) {
getMenuInflater().inflate(R.menu.fold_with_bug, menu);
} else {
getMenuInflater().inflate(R.menu.fold, menu);
}
Spinner s = (Spinner) menu.findItem(R.id.num_of_folds).getActionView();
s.setOnItemSelectedListener(mItemSelectedListener);
return true;
}
#Override
public void onWindowFocusChanged (boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
int[] loc = new int[2];
mFoldLayout.getLocationOnScreen(loc);
mParentPositionY = loc[1];
}
#Override
public boolean onTouchEvent(MotionEvent me) {
return mScrollGestureDetector.onTouchEvent(me);
}
#Override
public boolean onOptionsItemSelected (MenuItem item) {
switch(item.getItemId()) {
case R.id.animate_fold:
animateFold();
break;
case R.id.toggle_orientation:
mOrientation = (mOrientation == Orientation.HORIZONTAL) ? Orientation.VERTICAL :
Orientation.HORIZONTAL;
item.setTitle((mOrientation == Orientation.HORIZONTAL) ? R.string.vertical :
R.string.horizontal);
mTranslation = 0;
mFoldLayout.setOrientation(mOrientation);
break;
case R.id.camera_feed:
mIsCameraFeed = !mIsCameraFeed;
item.setTitle(mIsCameraFeed ? R.string.static_image : R.string.camera_feed);
item.setChecked(mIsCameraFeed);
if (mIsCameraFeed) {
mFoldLayout.removeView(mImageView);
mFoldLayout.addView(mTextureView, new ViewGroup.LayoutParams(
mFoldLayout.getWidth(), mFoldLayout.getHeight()));
} else {
mFoldLayout.removeView(mTextureView);
mFoldLayout.addView(mImageView, new ViewGroup.LayoutParams(
mFoldLayout.getWidth(), mFoldLayout.getHeight()));
}
mTranslation = 0;
break;
case R.id.sepia:
mIsSepiaOn = !mIsSepiaOn;
item.setChecked(!mIsSepiaOn);
if (mIsSepiaOn && mFoldLayout.getFoldFactor() != 0) {
setSepiaLayer(mFoldLayout.getChildAt(0), true);
} else {
setSepiaLayer(mFoldLayout.getChildAt(0), false);
}
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
public void animateFold ()
{
float foldFactor = mFoldLayout.getFoldFactor();
ObjectAnimator animator = ObjectAnimator.ofFloat(mFoldLayout, "foldFactor", foldFactor, 1);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.setRepeatCount(1);
animator.setDuration(FOLD_ANIMATION_DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
private class ItemSelectedListener implements OnItemSelectedListener {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
mNumberOfFolds = Integer.parseInt(parent.getItemAtPosition(pos).toString());
if (mDidLoadSpinner) {
mDidLoadSpinner = false;
} else {
mTranslation = 0;
mFoldLayout.setNumberOfFolds(mNumberOfFolds);
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
}
private class ScrollGestureDetector extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onDown (MotionEvent e) {
mDidNotStartScroll = true;
return true;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
int touchSlop = 0;
float factor;
if (mOrientation == Orientation.VERTICAL) {
factor = Math.abs((float)(mTranslation) / (float)(mFoldLayout.getHeight()));
if (e2.getY() - mParentPositionY <= mFoldLayout.getHeight()
&& e2.getY() - mParentPositionY >= 0) {
if ((e2.getY() - mParentPositionY) > mFoldLayout.getHeight() * mAnchorFactor) {
mTranslation -= (int)distanceY;
touchSlop = distanceY < 0 ? -mTouchSlop : mTouchSlop;
} else {
mTranslation += (int)distanceY;
touchSlop = distanceY < 0 ? mTouchSlop : -mTouchSlop;
}
mTranslation = mDidNotStartScroll ? mTranslation + touchSlop : mTranslation;
if (mTranslation < -mFoldLayout.getHeight()) {
mTranslation = -mFoldLayout.getHeight();
}
}
} else {
factor = Math.abs(((float)mTranslation) / ((float) mFoldLayout.getWidth()));
if (e2.getRawX() > mFoldLayout.getWidth() * mAnchorFactor) {
mTranslation -= (int)distanceX;
touchSlop = distanceX < 0 ? -mTouchSlop : mTouchSlop;
} else {
mTranslation += (int)distanceX;
touchSlop = distanceX < 0 ? mTouchSlop : -mTouchSlop;
}
mTranslation = mDidNotStartScroll ? mTranslation + touchSlop : mTranslation;
if (mTranslation < -mFoldLayout.getWidth()) {
mTranslation = -mFoldLayout.getWidth();
}
}
mDidNotStartScroll = false;
if (mTranslation > 0) {
mTranslation = 0;
}
mFoldLayout.setFoldFactor(factor);
return true;
}
}
}
//activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.android.foldinglayout.FoldingLayout
android:layout_weight="1"
android:id="#+id/fold_view"
android:layout_width="match_parent"
android:layout_height="0dp">
<ImageView
android:id="#+id/image_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="fitXY"/>
</com.example.android.foldinglayout.FoldingLayout>
<SeekBar
android:id="#+id/anchor_seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"/>
</LinearLayout>

Android Music Seekbar match_parent

Basically, I cloned a material design widget library and wanted to use the Seekbar view. Even when using match_parent for the width, there was still some padding on the left and right. To combat this, I cloned the project from GitHub and went to the Slider.java class to try and figure out how to truly make this a full length media SeekBar.
I've included my current code, which basically shows a full length seekbar, but starts it a little to the right from the beginning (and consequently stops a little to the left from the end). Here it is mid-media-playback:
CODE
public class Slider extends CustomView {
private int backgroundColor = Color.parseColor("#614E8D");
private Ball ball;
private Bitmap bitmap;
private int max = 100;
private int min = 0;
private NumberIndicator numberIndicator;
private OnValueChangedListener onValueChangedListener;
private boolean placedBall = false;
private boolean press = false;
private boolean showNumberIndicator = false;
private int value = 0;
public Slider(Context context, AttributeSet attrs) {
super(context, attrs);
setAttributes(attrs);
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getMin() {
return min;
}
public void setMin(int min) {
this.min = min;
}
public OnValueChangedListener getOnValueChangedListener() {
return onValueChangedListener;
}
public void setOnValueChangedListener(
OnValueChangedListener onValueChangedListener) {
this.onValueChangedListener = onValueChangedListener;
}
// GETERS & SETTERS
public int getValue() {
return value;
}
public void setValue(final int value) {
if (placedBall == false)
post(new Runnable() {
#Override
public void run() {
setValue(value);
}
});
else {
this.value = value;
float division = (ball.xFin - ball.xIni) / max;
ViewHelper.setX(ball,
value * division + getHeight() / 2 - ball.getWidth() / 2);
ball.changeBackground();
}
}
#Override
public void invalidate() {
ball.invalidate();
super.invalidate();
}
public boolean isShowNumberIndicator() {
return showNumberIndicator;
}
public void setShowNumberIndicator(boolean showNumberIndicator) {
this.showNumberIndicator = showNumberIndicator;
numberIndicator = (showNumberIndicator) ? new NumberIndicator(
getContext()) : null;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
isLastTouch = true;
if (isEnabled()) {
if (event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_MOVE) {
if (numberIndicator != null
&& numberIndicator.isShowing() == false)
numberIndicator.show();
if ((event.getX() <= getWidth() && event.getX() >= 0)) {
press = true;
// calculate value
int newValue = 0;
float division = (ball.xFin - ball.xIni) / (max - min);
if (event.getX() > ball.xFin) {
newValue = max;
} else if (event.getX() < ball.xIni) {
newValue = min;
} else {
newValue = min + (int) ((event.getX() - ball.xIni) / division);
}
if (value != newValue) {
value = newValue;
if (onValueChangedListener != null)
onValueChangedListener.onValueChanged(newValue);
}
// move ball indicator
float x = event.getX();
x = (x < ball.xIni) ? ball.xIni : x;
x = (x > ball.xFin) ? ball.xFin : x;
ViewHelper.setX(ball, x);
ball.changeBackground();
// If slider has number indicator
if (numberIndicator != null) {
// move number indicator
numberIndicator.indicator.x = x;
numberIndicator.indicator.finalY = Utils
.getRelativeTop(this) - getHeight() / 2;
numberIndicator.indicator.finalSize = getHeight() / 2;
numberIndicator.numberIndicator.setText("");
}
} else {
press = false;
isLastTouch = false;
if (numberIndicator != null)
numberIndicator.dismiss();
}
} else if (event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL) {
if (numberIndicator != null)
numberIndicator.dismiss();
isLastTouch = false;
press = false;
}
}
return true;
}
#Override
public void setBackgroundColor(int color) {
backgroundColor = color;
if (isEnabled())
beforeBackground = backgroundColor;
}
/**
* Make a dark color to press effect
*
* #return
*/
protected int makePressColor() {
int r = (this.backgroundColor >> 16) & 0xFF;
int g = (this.backgroundColor >> 8) & 0xFF;
int b = (this.backgroundColor >> 0) & 0xFF;
r = (r - 30 < 0) ? 0 : r - 30;
g = (g - 30 < 0) ? 0 : g - 30;
b = (b - 30 < 0) ? 0 : b - 30;
return Color.argb(70, r, g, b);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!placedBall) {
placeBall();
}
Paint paint = new Paint();
if (value == min) {
// Crop line to transparent effect
// before song loaded, basically. Need to make this similar to value != min
if (bitmap == null) {
bitmap = Bitmap.createBitmap(canvas.getWidth(),
canvas.getHeight(), Bitmap.Config.ARGB_8888);
}
Canvas temp = new Canvas(bitmap);
paint.setColor(Color.parseColor("#54457A")); //purple
paint.setStrokeWidth(Utils.dpToPx(2, getResources()));
// temp.drawLine(getHeight() / 2, getHeight() / 2, getWidth()
// - getHeight() / 2, getHeight() / 2, paint);
temp.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, paint);
Paint transparentPaint = new Paint();
transparentPaint.setColor(getResources().getColor(
android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
temp.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
ViewHelper.getY(ball) + ball.getHeight() / 2,
ball.getWidth() / 2, transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, new Paint());
} else {
/*TRACK*/
paint.setColor(Color.parseColor("#5A5A5C")); //track
paint.setStrokeWidth(Utils.dpToPx(10, getResources()));
canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, paint); //track length
paint.setColor(backgroundColor);
/*END TRACK*/
float division = (ball.xFin - ball.xIni) / (max - min);
int value = this.value - min;
//DO NOT TOUCH -- Progress coloring
canvas.drawLine(getHeight() / 2, getHeight() / 2, value * division
+ getHeight() / 2, getHeight() / 2, paint);
}
if (press && !showNumberIndicator) {
paint.setColor(backgroundColor);
paint.setAntiAlias(true);
canvas.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
getHeight() / 2, getHeight() / 3, paint);
}
invalidate();
}
// Set atributtes of XML to View
protected void setAttributes(AttributeSet attrs) {
setBackgroundResource(R.drawable.background_transparent);
// Set size of view
setMinimumHeight(Utils.dpToPx(48, getResources()));
setMinimumWidth(Utils.dpToPx(80, getResources()));
// Set background Color
// Color by resource
int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,
"background", -1);
if (bacgroundColor != -1) {
setBackgroundColor(getResources().getColor(bacgroundColor));
} else {
// Color by hexadecimal
int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
if (background != -1)
setBackgroundColor(background);
}
showNumberIndicator = attrs.getAttributeBooleanValue(MATERIALDESIGNXML,
"showNumberIndicator", false);
min = attrs.getAttributeIntValue(MATERIALDESIGNXML, "min", 0);
max = attrs.getAttributeIntValue(MATERIALDESIGNXML, "max", 0);
value = attrs.getAttributeIntValue(MATERIALDESIGNXML, "value", min);
ball = new Ball(getContext());
RelativeLayout.LayoutParams params = new LayoutParams(Utils.dpToPx(20,
getResources()), Utils.dpToPx(20, getResources()));
params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
ball.setLayoutParams(params);
addView(ball);
// Set if slider content number indicator
// TODO
if (showNumberIndicator) {
numberIndicator = new NumberIndicator(getContext());
}
}
private void placeBall() {
ViewHelper.setX(ball, getHeight() / 2 - ball.getWidth() / 2);
ViewHelper.setX(ball, ball.getWidth());
ball.xIni = ViewHelper.getX(ball);
ball.xFin = getWidth() - ball.getWidth();// - getHeight() / 2 - ball.getWidth() / 2;
ball.xCen = getWidth() / 2 - ball.getWidth() / 2;
placedBall = true;
}
// Event when slider change value
public interface OnValueChangedListener {
public void onValueChanged(int value);
}
class Ball extends View {
float xIni, xFin, xCen;
public Ball(Context context) {
super(context);
setBackgroundResource(R.drawable.background_switch_ball_uncheck);
}
public void changeBackground() {
if (value != min) {
setBackgroundResource(R.drawable.background_checkbox);
LayerDrawable layer = (LayerDrawable) getBackground();
GradientDrawable shape = (GradientDrawable) layer
.findDrawableByLayerId(R.id.shape_bacground);
shape.setColor(Color.parseColor("#D5C46A")); //yellow ball
} else {
setBackgroundResource(R.drawable.background_switch_ball_uncheck);
}
}
}
// Slider Number Indicator
class Indicator extends RelativeLayout {
boolean animate = true;
// Final size after animation
float finalSize = 0;
// Final y position after animation
float finalY = 0;
boolean numberIndicatorResize = false;
// Size of number indicator
float size = 0;
// Position of number indicator
float x = 0;
float y = 0;
public Indicator(Context context) {
super(context);
setBackgroundColor(getResources().getColor(
android.R.color.transparent));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (numberIndicatorResize == false) {
LayoutParams params = (LayoutParams) numberIndicator.numberIndicator
.getLayoutParams();
params.height = (int) finalSize * 2;
params.width = (int) finalSize * 2;
numberIndicator.numberIndicator.setLayoutParams(params);
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(backgroundColor);
if (animate) {
if (y == 0)
y = finalY + finalSize * 2;
y -= Utils.dpToPx(6, getResources());
size += Utils.dpToPx(2, getResources());
}
canvas.drawCircle(
ViewHelper.getX(ball)
+ Utils.getRelativeLeft((View) ball.getParent())
+ ball.getWidth() / 2, y, size, paint);
if (animate && size >= finalSize)
animate = false;
if (animate == false) {
ViewHelper
.setX(numberIndicator.numberIndicator,
(ViewHelper.getX(ball)
+ Utils.getRelativeLeft((View) ball
.getParent()) + ball.getWidth() / 2)
- size);
ViewHelper.setY(numberIndicator.numberIndicator, y - size);
numberIndicator.numberIndicator.setText(value + "");
}
invalidate();
}
}
class NumberIndicator extends Dialog {
Indicator indicator;
TextView numberIndicator;
public NumberIndicator(Context context) {
super(context, android.R.style.Theme_Translucent);
}
#Override
public void dismiss() {
super.dismiss();
indicator.y = 0;
indicator.size = 0;
indicator.animate = true;
}
#Override
public void onBackPressed() {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.number_indicator_spinner);
setCanceledOnTouchOutside(false);
RelativeLayout content = (RelativeLayout) this
.findViewById(R.id.number_indicator_spinner_content);
indicator = new Indicator(this.getContext());
content.addView(indicator);
numberIndicator = new TextView(getContext());
numberIndicator.setTextColor(Color.WHITE);
numberIndicator.setGravity(Gravity.CENTER);
content.addView(numberIndicator);
indicator.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT));
}
}
}
Any help on how to get the circle to start at the very left and end at the very right would be greatly appreciated.
Playing around some more, I found that the original developer of this Slider.java class used a lot of getHeight() / 2 which caused some padding that I didn't want. I've included the edited class. Credit for original class to navasmdc, the creator of Material Design Library.. Feel free to use this class if you need a full sized SeekBar
Slider.java
package com.gc.materialdesign.views;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gc.materialdesign.R;
import com.gc.materialdesign.utils.Utils;
import com.nineoldandroids.view.ViewHelper;
public class Slider extends CustomView {
private int backgroundColor = Color.parseColor("#614E8D");
private Ball ball;
private Bitmap bitmap;
private int max = 100;
private int min = 0;
private NumberIndicator numberIndicator;
private OnValueChangedListener onValueChangedListener;
private boolean placedBall = false;
private boolean press = false;
private boolean showNumberIndicator = false;
private int value = 0;
public Slider(Context context, AttributeSet attrs) {
super(context, attrs);
setAttributes(attrs);
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getMin() {
return min;
}
public void setMin(int min) {
this.min = min;
}
public OnValueChangedListener getOnValueChangedListener() {
return onValueChangedListener;
}
public void setOnValueChangedListener(
OnValueChangedListener onValueChangedListener) {
this.onValueChangedListener = onValueChangedListener;
}
// GETERS & SETTERS
public int getValue() {
return value;
}
public void setValue(final int value) {
if (placedBall == false)
post(new Runnable() {
#Override
public void run() {
setValue(value);
}
});
else {
this.value = value;
float division = (ball.xFin - ball.xIni) / max;
ViewHelper.setX(ball,
value* division);//value * division - ball.getWidth() / 2);
ball.changeBackground();
}
}
#Override
public void invalidate() {
ball.invalidate();
super.invalidate();
}
public boolean isShowNumberIndicator() {
return showNumberIndicator;
}
public void setShowNumberIndicator(boolean showNumberIndicator) {
this.showNumberIndicator = showNumberIndicator;
numberIndicator = (showNumberIndicator) ? new NumberIndicator(
getContext()) : null;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
isLastTouch = true;
if (isEnabled()) {
if (event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_MOVE) {
if (numberIndicator != null
&& numberIndicator.isShowing() == false)
numberIndicator.show();
if ((event.getX() <= getWidth() && event.getX() >= 0)) {
press = true;
// calculate value
int newValue = 0;
float division = (ball.xFin - ball.xIni) / (max - min);
if (event.getX() > ball.xFin) {
newValue = max;
} else if (event.getX() < ball.xIni) {
newValue = min;
} else {
newValue = min + (int) ((event.getX() - ball.xIni) / division);
}
if (value != newValue) {
value = newValue;
if (onValueChangedListener != null)
onValueChangedListener.onValueChanged(newValue);
}
// move ball indicator
float x = event.getX();
x = (x < ball.xIni) ? ball.xIni : x;
x = (x > ball.xFin) ? ball.xFin : x;
ViewHelper.setX(ball, x);
ball.changeBackground();
// If slider has number indicator
if (numberIndicator != null) {
// move number indicator
numberIndicator.indicator.x = x;
numberIndicator.indicator.finalY = Utils
.getRelativeTop(this) - getHeight() / 2;
numberIndicator.indicator.finalSize = getHeight() / 2;
numberIndicator.numberIndicator.setText("");
}
} else {
press = false;
isLastTouch = false;
if (numberIndicator != null)
numberIndicator.dismiss();
}
} else if (event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL) {
if (numberIndicator != null)
numberIndicator.dismiss();
isLastTouch = false;
press = false;
}
}
return true;
}
#Override
public void setBackgroundColor(int color) {
backgroundColor = color;
if (isEnabled())
beforeBackground = backgroundColor;
}
/**
* Make a dark color to press effect
*
* #return
*/
protected int makePressColor() {
int r = (this.backgroundColor >> 16) & 0xFF;
int g = (this.backgroundColor >> 8) & 0xFF;
int b = (this.backgroundColor >> 0) & 0xFF;
r = (r - 30 < 0) ? 0 : r - 30;
g = (g - 30 < 0) ? 0 : g - 30;
b = (b - 30 < 0) ? 0 : b - 30;
return Color.argb(70, r, g, b);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!placedBall) {
placeBall();
}
Paint paint = new Paint();
if (value == min) {
// Crop line to transparent effect
// before song loaded, basically. Need to make this similar to value != min
if (bitmap == null) {
bitmap = Bitmap.createBitmap(canvas.getWidth(),
canvas.getHeight(), Bitmap.Config.ARGB_8888);
}
Canvas temp = new Canvas(bitmap);
paint.setColor(Color.parseColor("#54457A")); //purple
paint.setStrokeWidth(Utils.dpToPx(2, getResources()));
// temp.drawLine(getHeight() / 2, getHeight() / 2, getWidth()
// - getHeight() / 2, getHeight() / 2, paint);
temp.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, paint);
Paint transparentPaint = new Paint();
transparentPaint.setColor(getResources().getColor(
android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
temp.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
ViewHelper.getY(ball) + ball.getHeight() / 2,
ball.getWidth() / 2, transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, new Paint());
} else {
/*TRACK*/
paint.setColor(Color.parseColor("#5A5A5C")); //track
paint.setStrokeWidth(Utils.dpToPx(10, getResources()));
canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, paint); //track length
paint.setColor(backgroundColor);
/*END TRACK*/
float division = (ball.xFin - ball.xIni) / (max - min);
int value = this.value - min;
//DO NOT TOUCH -- Progress coloring
canvas.drawLine(0, getHeight() / 2, value * division
+ball.getWidth(), getHeight() / 2, paint);
}
if (press && !showNumberIndicator) {
paint.setColor(backgroundColor);
paint.setAntiAlias(true);
canvas.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
getHeight() / 2, getHeight() / 3, paint);
}
invalidate();
}
// Set atributtes of XML to View
protected void setAttributes(AttributeSet attrs) {
setBackgroundResource(R.drawable.background_transparent);
// Set size of view
setMinimumHeight(Utils.dpToPx(48, getResources()));
setMinimumWidth(Utils.dpToPx(80, getResources()));
// Set background Color
// Color by resource
int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,
"background", -1);
if (bacgroundColor != -1) {
setBackgroundColor(getResources().getColor(bacgroundColor));
} else {
// Color by hexadecimal
int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
if (background != -1)
setBackgroundColor(background);
}
showNumberIndicator = attrs.getAttributeBooleanValue(MATERIALDESIGNXML,
"showNumberIndicator", false);
min = attrs.getAttributeIntValue(MATERIALDESIGNXML, "min", 0);
max = attrs.getAttributeIntValue(MATERIALDESIGNXML, "max", 0);
value = attrs.getAttributeIntValue(MATERIALDESIGNXML, "value", min);
ball = new Ball(getContext());
RelativeLayout.LayoutParams params = new LayoutParams(Utils.dpToPx(20,
getResources()), Utils.dpToPx(20, getResources()));
params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
ball.setLayoutParams(params);
addView(ball);
// Set if slider content number indicator
// TODO
if (showNumberIndicator) {
numberIndicator = new NumberIndicator(getContext());
}
}
private void placeBall() {
// ViewHelper.setX(ball, getHeight() / 2 - ball.getWidth() / 2);
// ViewHelper.setX(ball, 0);
ViewHelper.setX(ball, ball.getWidth());
ball.xIni = 0;//ViewHelper.getX(ball);
ball.xFin = getWidth() - ball.getWidth();// - getHeight() / 2 - ball.getWidth() / 2;
ball.xCen = getWidth() / 2 - ball.getWidth() / 2;
placedBall = true;
}
// Event when slider change value
public interface OnValueChangedListener {
public void onValueChanged(int value);
}
class Ball extends View {
float xIni, xFin, xCen;
public Ball(Context context) {
super(context);
setBackgroundResource(R.drawable.background_switch_ball_uncheck);
}
public void changeBackground() {
if (value != min) {
setBackgroundResource(R.drawable.background_checkbox);
LayerDrawable layer = (LayerDrawable) getBackground();
GradientDrawable shape = (GradientDrawable) layer
.findDrawableByLayerId(R.id.shape_bacground);
shape.setColor(Color.parseColor("#D5C46A")); //yellow ball
} else {
setBackgroundResource(R.drawable.background_switch_ball_uncheck);
}
}
}
// Slider Number Indicator
class Indicator extends RelativeLayout {
boolean animate = true;
// Final size after animation
float finalSize = 0;
// Final y position after animation
float finalY = 0;
boolean numberIndicatorResize = false;
// Size of number indicator
float size = 0;
// Position of number indicator
float x = 0;
float y = 0;
public Indicator(Context context) {
super(context);
setBackgroundColor(getResources().getColor(
android.R.color.transparent));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (numberIndicatorResize == false) {
LayoutParams params = (LayoutParams) numberIndicator.numberIndicator
.getLayoutParams();
params.height = (int) finalSize * 2;
params.width = (int) finalSize * 2;
numberIndicator.numberIndicator.setLayoutParams(params);
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(backgroundColor);
if (animate) {
if (y == 0)
y = finalY + finalSize * 2;
y -= Utils.dpToPx(6, getResources());
size += Utils.dpToPx(2, getResources());
}
canvas.drawCircle(
ViewHelper.getX(ball)
+ Utils.getRelativeLeft((View) ball.getParent())
+ ball.getWidth() / 2, y, size, paint);
if (animate && size >= finalSize)
animate = false;
if (animate == false) {
ViewHelper
.setX(numberIndicator.numberIndicator,
(ViewHelper.getX(ball)
+ Utils.getRelativeLeft((View) ball
.getParent()) + ball.getWidth() / 2)
- size);
ViewHelper.setY(numberIndicator.numberIndicator, y - size);
numberIndicator.numberIndicator.setText(value + "");
}
invalidate();
}
}
class NumberIndicator extends Dialog {
Indicator indicator;
TextView numberIndicator;
public NumberIndicator(Context context) {
super(context, android.R.style.Theme_Translucent);
}
#Override
public void dismiss() {
super.dismiss();
indicator.y = 0;
indicator.size = 0;
indicator.animate = true;
}
#Override
public void onBackPressed() {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.number_indicator_spinner);
setCanceledOnTouchOutside(false);
RelativeLayout content = (RelativeLayout) this
.findViewById(R.id.number_indicator_spinner_content);
indicator = new Indicator(this.getContext());
content.addView(indicator);
numberIndicator = new TextView(getContext());
numberIndicator.setTextColor(Color.WHITE);
numberIndicator.setGravity(Gravity.CENTER);
content.addView(numberIndicator);
indicator.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT));
}
}
}

Canvas doesn't draw correctly my scale text

I see scale with only 0 written! As in the picture and two strange zeros out of the schema: (GALAXY NEXUS 4.2.1)
As in the example at http://mindtherobot.com/blog/272/android-custom-ui-making-a-vintage-thermometer/comment-page-1/#comment-106122%29 this is my custom view:
package com.wikibuyers.barometro;
import java.util.List;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LightingColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class Barometro extends View implements SensorEventListener{
private static final String TAG = Barometro.class.getSimpleName();
private Handler handler;
// drawing tools
private RectF rimRect;
private Paint rimPaint;
private Paint rimCirclePaint;
private RectF faceRect;
private Bitmap faceTexture;
private Paint facePaint;
private Paint rimShadowPaint;
private Paint scalePaint;
private RectF scaleRect;
private Paint titlePaint;
private Path titlePath;
private Paint logoPaint;
private Bitmap logo;
private Matrix logoMatrix;
private float logoScale;
private Paint handPaint;
private Path handPath;
private Paint handScrewPaint;
private Paint backgroundPaint;
// end drawing tools
private Bitmap background; // holds the cached static part
// scale configuration
private static final int totalNicks = 100;
private static final float degreesPerNick = 360.0f / totalNicks;
private static final int centerDegree = 40; // the one in the top center (12 o'clock)
private static final int minDegrees = -30;
private static final int maxDegrees = 110;
// hand dynamics -- all are angular expressed in F degrees
private boolean handInitialized = false;
private float handPosition = centerDegree;
private float handTarget = centerDegree;
private float handVelocity = 0.0f;
private float handAcceleration = 0.0f;
private long lastHandMoveTime = -1L;
public Barometro(Context context) {
super(context);
init();
}
public Barometro(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Barometro(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
attachToSensor();
}
#Override
protected void onDetachedFromWindow() {
detachFromSensor();
super.onDetachedFromWindow();
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
Parcelable superState = bundle.getParcelable("superState");
super.onRestoreInstanceState(superState);
handInitialized = bundle.getBoolean("handInitialized");
handPosition = bundle.getFloat("handPosition");
handTarget = bundle.getFloat("handTarget");
handVelocity = bundle.getFloat("handVelocity");
handAcceleration = bundle.getFloat("handAcceleration");
lastHandMoveTime = bundle.getLong("lastHandMoveTime");
}
#Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
Bundle state = new Bundle();
state.putParcelable("superState", superState);
state.putBoolean("handInitialized", handInitialized);
state.putFloat("handPosition", handPosition);
state.putFloat("handTarget", handTarget);
state.putFloat("handVelocity", handVelocity);
state.putFloat("handAcceleration", handAcceleration);
state.putLong("lastHandMoveTime", lastHandMoveTime);
return state;
}
#SuppressLint({ "NewApi", "InlinedApi" })
private void init() {
handler = new Handler();
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
initDrawingTools();
}
private String getTitle() {
return "wikibuyers.com";
}
private SensorManager getSensorManager() {
return (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
}
private void attachToSensor() {
SensorManager sensorManager = getSensorManager();
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_PRESSURE);
if (sensors.size() > 0) {
Sensor sensor = sensors.get(0);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, handler);
} else {
Log.e(TAG, "No pressure sensor found");
}
}
private void detachFromSensor() {
SensorManager sensorManager = getSensorManager();
sensorManager.unregisterListener(this);
}
private void initDrawingTools() {
rimRect = new RectF(0.1f, 0.1f, 0.9f, 0.9f);
// the linear gradient is a bit skewed for realism
rimPaint = new Paint();
rimPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
rimPaint.setShader(new LinearGradient(0.40f, 0.0f, 0.60f, 1.0f,
Color.rgb(0xf0, 0xf5, 0xf0),
Color.rgb(0x30, 0x31, 0x30),
Shader.TileMode.CLAMP));
rimCirclePaint = new Paint();
rimCirclePaint.setAntiAlias(true);
rimCirclePaint.setStyle(Paint.Style.STROKE);
rimCirclePaint.setColor(Color.argb(0x4f, 0x33, 0x36, 0x33));
rimCirclePaint.setStrokeWidth(0.005f);
float rimSize = 0.02f;
faceRect = new RectF();
faceRect.set(rimRect.left + rimSize, rimRect.top + rimSize,
rimRect.right - rimSize, rimRect.bottom - rimSize);
faceTexture = BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.plastic);
BitmapShader paperShader = new BitmapShader(faceTexture,
Shader.TileMode.MIRROR,
Shader.TileMode.MIRROR);
Matrix paperMatrix = new Matrix();
facePaint = new Paint();
facePaint.setFilterBitmap(true);
paperMatrix.setScale(1.0f / faceTexture.getWidth(),
1.0f / faceTexture.getHeight());
paperShader.setLocalMatrix(paperMatrix);
facePaint.setStyle(Paint.Style.FILL);
facePaint.setShader(paperShader);
rimShadowPaint = new Paint();
rimShadowPaint.setShader(new RadialGradient(0.5f, 0.5f, faceRect.width() / 2.0f,
new int[] { 0x00000000, 0x00000500, 0x50000500 },
new float[] { 0.96f, 0.96f, 0.99f },
Shader.TileMode.MIRROR));
rimShadowPaint.setStyle(Paint.Style.FILL);
scalePaint = new Paint();
scalePaint.setStyle(Paint.Style.STROKE);
scalePaint.setColor(0x9f004d0f);
scalePaint.setStrokeWidth(0.005f);
scalePaint.setAntiAlias(true);
scalePaint.setTextSize(0.045f);
scalePaint.setTypeface(Typeface.SANS_SERIF);
scalePaint.setTextScaleX(0.8f);
scalePaint.setTextAlign(Paint.Align.CENTER);
float scalePosition = 0.10f;
scaleRect = new RectF();
scaleRect.set(faceRect.left + scalePosition, faceRect.top + scalePosition,
faceRect.right - scalePosition, faceRect.bottom - scalePosition);
titlePaint = new Paint();
titlePaint.setColor(0xaf946109);
titlePaint.setAntiAlias(true);
titlePaint.setTypeface(Typeface.DEFAULT_BOLD);
titlePaint.setTextAlign(Paint.Align.CENTER);
titlePaint.setTextSize(0.05f);
titlePaint.setTextScaleX(0.8f);
titlePath = new Path();
titlePath.addArc(new RectF(0.24f, 0.24f, 0.76f, 0.76f), -180.0f, -180.0f);
logoPaint = new Paint();
logoPaint.setFilterBitmap(true);
logo = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.logo);
logoMatrix = new Matrix();
logoScale = (1.0f / logo.getWidth()) * 0.3f;;
logoMatrix.setScale(logoScale, logoScale);
handPaint = new Paint();
handPaint.setAntiAlias(true);
handPaint.setColor(0xff392f2c);
handPaint.setShadowLayer(0.01f, -0.005f, -0.005f, 0x7f000000);
handPaint.setStyle(Paint.Style.FILL);
handPath = new Path();
handPath.moveTo(0.5f, 0.5f + 0.2f);
handPath.lineTo(0.5f - 0.010f, 0.5f + 0.2f - 0.007f);
handPath.lineTo(0.5f - 0.002f, 0.5f - 0.32f);
handPath.lineTo(0.5f + 0.002f, 0.5f - 0.32f);
handPath.lineTo(0.5f + 0.010f, 0.5f + 0.2f - 0.007f);
handPath.lineTo(0.5f, 0.5f + 0.2f);
handPath.addCircle(0.5f, 0.5f, 0.025f, Path.Direction.CW);
handScrewPaint = new Paint();
handScrewPaint.setAntiAlias(true);
handScrewPaint.setColor(0xff493f3c);
handScrewPaint.setStyle(Paint.Style.FILL);
backgroundPaint = new Paint();
backgroundPaint.setFilterBitmap(true);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, "Width spec: " + MeasureSpec.toString(widthMeasureSpec));
Log.d(TAG, "Height spec: " + MeasureSpec.toString(heightMeasureSpec));
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int chosenWidth = chooseDimension(widthMode, widthSize);
int chosenHeight = chooseDimension(heightMode, heightSize);
int chosenDimension = Math.min(chosenWidth, chosenHeight);
setMeasuredDimension(chosenDimension, chosenDimension);
}
private int chooseDimension(int mode, int size) {
if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {
return size;
} else { // (mode == MeasureSpec.UNSPECIFIED)
return getPreferredSize();
}
}
// in case there is no size specified
private int getPreferredSize() {
return 300;
}
private void drawRim(Canvas canvas) {
// first, draw the metallic body
canvas.drawOval(rimRect, rimPaint);
// now the outer rim circle
canvas.drawOval(rimRect, rimCirclePaint);
}
private void drawFace(Canvas canvas) {
canvas.drawOval(faceRect, facePaint);
// draw the inner rim circle
canvas.drawOval(faceRect, rimCirclePaint);
// draw the rim shadow inside the face
canvas.drawOval(faceRect, rimShadowPaint);
}
private void drawScale(Canvas canvas) {
canvas.drawOval(scaleRect, scalePaint);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
for (int i = 0; i < totalNicks; ++i) {
float y1 = scaleRect.top;
float y2 = y1 - 0.020f;
canvas.drawLine(0.5f, y1, 0.5f, y2, scalePaint);
if ((i % 5) == 0) {
int value = nickToDegree(i);
if ((value >= minDegrees) && (value <= maxDegrees)) {
String valueString = Integer.toString(value);
canvas.drawText(valueString, 0.5f, y2 - 0.015f, scalePaint);
}
}
canvas.rotate(degreesPerNick, 0.5f, 0.5f);
}
canvas.restore();
}
private int nickToDegree(int nick) {
int rawDegree = ((nick < totalNicks / 2) ? nick : (nick - totalNicks)) * 2;
int shiftedDegree = rawDegree + centerDegree;
return shiftedDegree;
}
private float degreeToAngle(float degree) {
return (degree - centerDegree) / 2.0f * degreesPerNick;
}
private void drawTitle(Canvas canvas) {
String title = getTitle();
canvas.drawTextOnPath(title, titlePath, 0.0f,0.0f, titlePaint);
}
private void drawLogo(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(0.5f - logo.getWidth() * logoScale / 2.0f,
0.5f - logo.getHeight() * logoScale / 2.0f);
int color = 0x00000000;
float position = getRelativePressurePosition();
if (position < 0) {
color |= (int) ((0xf0) * -position); // blue
} else {
color |= ((int) ((0xf0) * position)) << 16; // red
}
//Log.d(TAG, "*** " + Integer.toHexString(color));
LightingColorFilter logoFilter = new LightingColorFilter(0xff338822, color);
logoPaint.setColorFilter(logoFilter);
canvas.drawBitmap(logo, logoMatrix, logoPaint);
canvas.restore();
}
private void drawHand(Canvas canvas) {
if (handInitialized) {
float handAngle = degreeToAngle(handPosition);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(handAngle, 0.5f, 0.5f);
canvas.drawPath(handPath, handPaint);
canvas.restore();
canvas.drawCircle(0.5f, 0.5f, 0.01f, handScrewPaint);
}
}
private void drawBackground(Canvas canvas) {
if (background == null) {
Log.w(TAG, "Background not created");
} else {
canvas.drawBitmap(background, 0, 0, backgroundPaint);
}
}
#Override
protected void onDraw(Canvas canvas) {
drawBackground(canvas);
float scale = (float) getWidth();
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(scale, scale);
drawLogo(canvas);
drawHand(canvas);
canvas.restore();
if (handNeedsToMove()) {
moveHand();
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.d(TAG, "Size changed to " + w + "x" + h);
regenerateBackground();
}
private void regenerateBackground() {
// free the old bitmap
if (background != null) {
background.recycle();
}
background = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas backgroundCanvas = new Canvas(background);
float scale = (float) getWidth();
backgroundCanvas.scale(scale, scale);
drawRim(backgroundCanvas);
drawFace(backgroundCanvas);
drawScale(backgroundCanvas);
drawTitle(backgroundCanvas);
}
private boolean handNeedsToMove() {
return Math.abs(handPosition - handTarget) > 0.001f;
}
private void moveHand() {
if (! handNeedsToMove()) {
return;
}
if (lastHandMoveTime != -1L) {
long currentTime = System.currentTimeMillis();
float delta = (currentTime - lastHandMoveTime) / 1000.0f;
float direction = Math.signum(handVelocity);
if (Math.abs(handVelocity) < 90.0f) {
handAcceleration = 5.0f * (handTarget - handPosition);
} else {
handAcceleration = 0.0f;
}
handPosition += handVelocity * delta;
handVelocity += handAcceleration * delta;
if ((handTarget - handPosition) * direction < 0.01f * direction) {
handPosition = handTarget;
handVelocity = 0.0f;
handAcceleration = 0.0f;
lastHandMoveTime = -1L;
} else {
lastHandMoveTime = System.currentTimeMillis();
}
invalidate();
} else {
lastHandMoveTime = System.currentTimeMillis();
moveHand();
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (sensorEvent.values.length > 0) {
float pressureAtm = sensorEvent.values[0]/20;
//Log.i(TAG, "*** Temperature: " + temperatureC);
float pressureMmg = (9.0f / 5.0f) * pressureAtm + 32.0f;
setHandTarget(pressureAtm);
} else {
Log.w(TAG, "Empty sensor event received");
}
}
private float getRelativePressurePosition() {
if (handPosition < centerDegree) {
return - (centerDegree - handPosition) / (float) (centerDegree - minDegrees);
} else {
return (handPosition - centerDegree) / (float) (maxDegrees - centerDegree);
}
}
private void setHandTarget(float pressure) {
if (pressure < minDegrees) {
pressure = minDegrees;
} else if (pressure > maxDegrees) {
pressure = maxDegrees;
}
handTarget = pressure;
handInitialized = true;
invalidate();
}
}
This is focus on drawScale() method:
private void drawScale(Canvas canvas) {
canvas.drawOval(scaleRect, scalePaint);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
for (int i = 0; i < totalNicks; ++i) {
float y1 = scaleRect.top;
float y2 = y1 - 0.020f;
canvas.drawLine(0.5f, y1, 0.5f, y2, scalePaint);
if ((i % 5) == 0) {
int value = nickToDegree(i);
if ((value >= minDegrees) && (value <= maxDegrees)) {
String valueString = Integer.toString(value);
canvas.drawText(valueString, 0.5f, y2 - 0.015f, scalePaint);
}
}
canvas.rotate(degreesPerNick, 0.5f, 0.5f);
}
canvas.restore();
}

Categories

Resources