How to scroller scroll smoothly? - java

My problem is when I'm using scroller and draw canvas on it. It will scroll smoothly but when I draw bitmap + canvas the scroller scroll very slow means it is heavy to scroll thats why it scroll very slow fashion.
How to solve this problem?

I have no experience with OpenGL nor accelerometer, but swipe (called fling in Android's API) is not hard to achieve. First thing you need when making such a custom View, is implementing a GestureDetector and call its onTouchEvent() in your view's onTouchEvent()
GestureDetector mGD = new GestureDetector(getContext(),
new SimpleOnGestureListener() {
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// beware, it can scroll to infinity
scrollBy((int)distanceX, (int)distanceY);
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float vX, float vY) {
mScroller.fling(getScrollX(), getScrollY(),
-(int)vX, -(int)vY, 0, (int)mMaxScrollX, 0, (int)mMaxScrollY);
invalidate(); // don't remember if it's needed
return true;
}
#Override
public boolean onDown(MotionEvent e) {
if(!mScroller.isFinished() ) { // is flinging
mScroller.forceFinished(true); // to stop flinging on touch
}
return true; // else won't work
}
});
#Override
public boolean onTouchEvent(MotionEvent event) {
return mGD.onTouchEvent(event);
}
While OnGestureListener.onScroll() calls directly View.scrollBy(), for the onFling() method you'll need a Scroller.
Scroller is a simple object that, as reference says, encapsulates scrolling. It can be used for continuous scrolling or to react to flings. Scroller.fling() begin a "simulation" of fling scroll inside itself, and by watching it you can copy its smoothness with a continuous redrawing animation:
#Override
protected void onDraw(Canvas canvas) {
// ....your drawings....
// scrollTo invalidates, so until animation won't finish it will be called
// (used after a Scroller.fling() )
if(mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
}
}
that is, until animation is running, calculate the point we reached and scroll there.
As a last note: remember to return true in your OnGestureListener.onDown(), even if you don't want to do anything on down, or it won't work.
And be careful, because Scroller in Android 2.2 has a bug for which the fling animation will not actually end even if it reaches the limits you passed as arguments (yet computed offset respects them, so it won't actually move).

Related

How do I add touch controls to an Object in libGDX?

I'm making a balloon popping game for android in libGDX and I'm currently stuck on how to make the balloons pop when the user touches them. I tried using the touchDown() method,
b = new Balloon();
b.addListener(
new InputListener()
{
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
{
b.remove();
popped++;
return true;
}
});
mainStage.addActor(b);
}
but it doesn't work. I need a way so that only the balloons that I touch get popped and the others don't.
p.s I'm still learing libGDX so I'm a pretty big noob at it.
Edit: The Balloon is an Actor, and I did set the InputProcessor as well. The touch thing works but it doesn't pop the balloon that I touch it only pops the balloons that spawn at the starting x-axis.
At first you have to set your stage as input processor with Gdx.input.setInputProcessor(mainStage)
Then you can just add a ClickListener where you override the clicked method like this:
b.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
//YOUR_CODE
}
});

onTouch calling invalidate onDraw - not smooth

I have a code in my custom view, where if I touch, a circle is drawn. When I move the circle follow along. Code as below
// override onDraw
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (circleBounds != null) {
canvas.drawArc(circleBounds, 360, 360, false, mPaint);
}
}
// when ACTION_DOWN start touch according to the x,y values
private void startTouch(float x, float y) {
mPath.moveTo(x, y);
mX = x;
mY = y;
circleBounds.set(mX - mRadius, mY - mRadius, mX + mRadius, mY + mRadius);
invalidate();
}
//override the onTouchEvent
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTouch(x, y);
break;
case MotionEvent.ACTION_MOVE:
startTouch(x, y);
break;
}
return true;
}
When I move slowly, the movement is smooth. But when I move fast, one could feel the flickering. I guess invalidate() happens many time, causing the flickering. Is there a way to make it smoother (reduce the flickering on the drawn circle)?
Invalidate is not your issue, the system has double buffering, and you should not see a flicker.
From your code, I can think of 2 way to improve:
in onStartTouch you call mPath.moveTo(). It is not clear why you need mPath, but this path will keep growing and growing and will need more memory
canvas.drawArc is rendered by by CPU (it creates a bitmap and draws the arc into it on every call to onDraw). It would be faster to render yourself the circle once into a bitmap, and draw that bitmap in onDraw. If you keep using the same bitmap, it will be loaded once to the GPU and drawing will be much faster
I know this question is old, but in case someone else has same problem, the solution is to use postInvalidate() instead of the invalidate() in the onTouchEvent method, which will make it much more fluid.
As we receive many events in onTouchEvent, it's more effective to put invalidate call into events queue for future processing instead of doing it immediately.
public class MyView extend FrameLayout implement OnTouchListener{
public MyView(params){
init();
}
private void init(){
ImageView imageView = new ImageView();
imageView.setImageResource(R.mipmap.logo);
addView(imageview)
imageView.setOnTouchListener(this);
}
private boolean onTouch(params){
//some logic to control
//use imageView.setLayoutParams() instead of invalidate();
}
}

Set the Actor's sprite to the default

I'm having troubles with my Actor objects. When I click on the Button Actor, I want it to switch the Screen. When I do this, and I return to the last screen, the button that I clicked is still being hovered until I move my mouse again:
The code that I have for it:
// Load Game
textButtons[1].addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
// GameState is a subclass of Screen,
// GameStateManager helps me to manage my GameStates.
game.setGameState(GameStateManager.get("screenLoadGame"));
}
});
I've tried to "trick" it to fix this, by using the keyUp method, and doing the following:
#Override
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
int[] mousePos = { Gdx.input.getX(), Gdx.input.getY() };
Gdx.input.setCursorPosition(0, 0);
stage.act(1);
game.setGameState(GameStateManager.get("screenLoadGame"));
Gdx.input.setCursorPosition(mousePos[0], mousePos[1]);
}
But it doesn't work.
In the end, I want to be able to switch from one Screen back to the Main Menu Screen, and have the button as its default sprite. Is there a way to set an Actor's (Button's) Sprite?
NOTE: For the sprites (in the Json file) The up/down is how "Start New Game" shows it. The over sprite is when it has the gray background (like "Load Game").
Use a ChangeListener instead of a ClickListener. This will also allow your buttons to behave like buttons are expected to (if you click down and move your cursor off the button before releasing, it won't fire).
You can use a single ChangeListener for many buttons quite easily to keep your code tidy.
ChangeListener changeListener = new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
if (actor == startNewGameButton){
startNewGame();
} else if (actor == loadGameButton){
loadGame();
} else if (actor == creditsButton){
showCreditsScreen();
}
}
};
And then to add it to a button:
startNewGameButton.addListener(changeListener);

How to get if image is touched and not the transparent background? LIBGDX

i have a picture of a head and its on a transparent background and i want to get if the head is clicked not the area behind his head. this is what i had for the entire image not the image withing the box. pretend the grey part is the transparent part. i want nothing to happen when that area is clicked. only his body.
link to picture->link to picture
stage.addListener(new ClickListener()
{
#Override
public boolean touchDown(InputEvent event, float x, float y, int a , int b)
{
if(box.equals(stage.hit(x,y,false)))
{
box.setPosition(100, 100);
point.play();
score++;
}
return true;
}
});

Android horizontal text scroll - automatic and by gesture

I'm relatively new to Android programming, and I need a control that holds text and scrolls automatically. Now, I know about the "marquee" in the TextView control and it works fine for what it's intended, but that approach has two problems.
1) I need the text to scroll regardless of its length, i.e. if the text is only "Hello", and the control is set to match parents width, it needs to scroll.
2) The control needs to respond to user scroll - by flicking/dragging it left/right, the text should also scroll.
And naturally, when the text is "gone" to the left side, it should reappear on the right side and continue scrolling. For now, it should be a single line text.
Does anything like that exist, and if not, what would be the best approach guidelines to implementing it?
I ended up extending the default TextView, and pulling out Marquee class from TextView source. From there it's easy to modify the Marquee class so that it starts/stops when needed, and no longer requires the TextView to be selected (if that requirement is necessary).
To implement slide by gesture, the base class implements OnGestureListener and in onScroll(...) I update the offset in Marquee class, so when the View is drawn the next time it applies the new scroll offset.
And finally, to actually scroll by the amount needed, in the constructor I set the custom scroller, and in onDraw apply the scroll.
The important parts of code:
public class MarqueeTextView extends TextView implements OnGestureListener {
private GestureDetector gestureDetector;
private Marquee marquee;
private Scroller scroller;
// constructor
public MarqueeTextView(Context context, AttributeSet attrs) {
this.marquee = new Marquee(this);
this.scroller = new Scroller(context);
this.setScroller(scroller);
gestureDetector = new GestureDetector(getContext(), this);
// when enabled, longpress disables further movement tracking
gestureDetector.setIsLongpressEnabled(false);
}
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
marquee.addToScroll(distanceX);
return false;
}
// onDraw
protected void onDraw(Canvas canvas) {
scroller.setFinalX((int) marquee.mScroll);
super.onDraw(canvas);
}
// Marquee handler
private static final class Marquee extends Handler {
// mostly the same as original
// ...
float mScroll;
public void addToScroll(float amount) {
mScroll += amount;
// detect if needs to start over
}
}
}

Categories