I've found the solution for this problem, but it doesn't work quite well. It will restore some position but not exactly. If put some headline at the top, on rotation it won't be the same title on top but it won't put it back at the top too. I have different portrait and landscape UI, so I used this code
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putIntArray(SCROLL_STATE_KEY, new int[]{mScrollView.getScrollX(),
mScrollView.getScrollY()});
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
final int[] scrollPosition = savedInstanceState.getIntArray(SCROLL_STATE_KEY);
if(scrollPosition != null) {
mScrollView.post(new Runnable() {
#Override
public void run() {
mScrollView.scrollTo(scrollPosition[0], scrollPosition[1]);
}
});
}
}
Here's the gif. It is too fast but, I can't put more than 2MB here, so , hope you can see what's not working properly
Not the solution as sourcecode but an idea how to do this userfriendly:
Before rotation I would get the (text) content of the first visible few words/images of the scrollview and try to scroll the scrollview so that these words/images are on top of the scrollview again after the rotation.
I hav-nt done this for floating text yet but successfully for listviews and grids.
Related
I am making an app that has a list of two items that have two gifs, one in each (the same gif). As you can see in the video, when you click on the gif, the gif is not shown in motion and it is shown as a solid image, but when you click the right or left arrow it is shown correctly in motion despite that the function to load the gif is called in both the OnCreate function and the btn_next.setOnClickListener() function and the btn_prev.setOnClickListener() function. So the same thing is done but onCreate() the gif is not shown in motion and on btn_next and btn_prev setOnClickListener() it is shown. Please, someone could tell me what could be happening here? Bcause actually the same code is executed but on the first clikc is not working
Video: https://youtube.com/shorts/S5fDsqu3CeI?feature=share
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialog);
init();
glide();
}
private void init() {
img_1 = findViewById(R.id.img_image1);
btn_prev = findViewById(R.id.dialog_btn_prev);
btn_next = findViewById(R.id.dialog_btn_next);
btn_next.setOnClickListener(view -> {
glide();
});
btn_prev.setOnClickListener(view -> {
glide();
}
});
}
public void glide() {
Glide.with(getApplicationContext()).load(R.drawable.earth).into(img_1);
}
Change your code when you are initialising Glide with this.
Glide.with(this).asGif().load(R.raw. earth).into(img_1);
Try this!
Glide.with(this)
.asGif()
.load(R.raw._img)
.centerCrop()
.into(new ImageViewTarget<GifDrawable>(img) {
#Override
protected void setResource(#Nullable GifDrawable resource) {
img.setImageDrawable(resource);
}
});
Add dependencies build.gradle(App Level)
implementation 'com.github.bumptech.glide:glide:4.13.2'
I have a ViewPager in my app, and I'd like it to shake when it is loaded for the first time. This is to show the user that there are more pages available. How can I achieve that programmatically?
However, I don't want the pager to automatically scroll to the next page.
ViewPager has a method for swiping programmatically: fakeDragBy
https://developer.android.com/reference/android/support/v4/view/ViewPager.html#fakeDragBy(float)
Here's how you can achieve this:
Call viewPager.beginFakeDrag()
Start an animator. In the AnimatorUpdateListener override onAnimationUpdate so it calls viewPager.fakeDragBy()
In the AnimatorListener override onAnimationEnd so it calls viewPager.endFakeDrag() After this call, the ViewPager should settle back to the initial page.
vpaliyX's answer using translation won't show the next page. You need to use fakeDragBy so that the user can briefly see the edge of the next page.
As requested, here is a code snippet:
private float drag;
...
#Override
protected void onResume() {
super.onResume();
mViewPager.postDelayed(new Runnable() {
#Override
public void run() {
mViewPager.beginFakeDrag();
drag = 0;
float density = getResources().getDisplayMetrics().density;
// 120 is the number of dps you want the page to move in total
ValueAnimator animator = ValueAnimator.ofFloat(0, 120 * density);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float progress = (float) valueAnimator.getAnimatedValue();
mViewPager.fakeDragBy(drag - progress);
drag = progress;
}
});
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) { }
#Override
public void onAnimationEnd(Animator animator) {
mViewPager.endFakeDrag();
}
#Override
public void onAnimationCancel(Animator animator) { }
#Override
public void onAnimationRepeat(Animator animator) { }
});
animator.setDuration(400);
animator.start();
}
}, 300);
}
I put in a 300 ms start delay. I don't really know if that's necessary or not.
Note the expression drag - progress which gives a negative number. To get a leftward swipe, you have to use a negative value.
Also note that I didn't include any code to determine if this was the first time the app was opened.
You can play with the start delay, the animation duration, and the number of dps to swipe until you get the effect you are looking for.
If you want to shake it, you can use animation for it.
I had done the same stuff for FloatingActionButton, and it worked perfectly.
For ViewPager check out this code:
ObjectAnimator shakeAnimation=ObjectAnimator.ofFloat(yourViewPager,View.TRANSLATION_X,-25f,25f);
shakeAnimation.setDuration(100);
shakeAnimation.setRepeatCount(2);
shakeAnimation.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
yourViewPager.setTranslationY(0f);
}
});
shakeAnimation.start();
You can adjust the translation as convenient for, in my case it's just [-25,25].Also you can set a duration of animation, and the repeat count.
You can use this code for your ViewPager when the data has been loaded for the first time, however, you need to determine when the data has been loaded for the first time. But I don't think you will have problems with that.
Good luck!
I'm still learning how to program in Android and I created an Activity with a start view:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
mMainView = (RajawaliSurfaceView) findViewById(R.id.my_view);
mMainView.setSurfaceRenderer(new Renderer());
mMainView.setZOrderOnTop(false);
// Also set up a surface view I'd like to switch on back and forth
mGLView = new GLSurfaceView(this);
mGLView.setEGLContextClientVersion(2);
mGLView.setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR);
mGLView.setRenderer(cameraRenderer_ = new GLRenderer(this));
mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
This works and I can even switch to the GL view seamlessly:
public void switchToGLView(View view) {
setContentView(mGLView);
}
But after I'm done with the GL thing, I have the GLRenderer call a restore function in my main activity
public void restoreRenderer() {
// Restoring the previous view (my_view) with the non-GL renderer
setContentView(mMainView); <<<<<< FREEZES HERE (blackscreen)
}
and unfortunately this never works: the screen remains black from the previous GL renderer and by debugging the setContentView line I discovered that:
I don't get ANY error or warning log in the Android Monitor
The execution NEVER continues. It gets stuck in there forever
Any tips or hints on how to solve this?
You could solve this problem using a Frame or Relative layout.
If I understand correctly, both mMainView and mGLView are fullscreen.
There are a few options:
You could change the visibility of the views:
public void switchViews() {
if(mMainView.getVisibility() == View.VISIBLE){
mMainView.setVisibility(View.GONE);
mGLView.setVisibility(View.VISIBLE);
} else{
mMainView.setVisibility(View.VISIBLE);
mGLView.setVisibility(View.GONE);
}
}
The other option is to change the Z order of the views:
public void switchViews(View view){
view.bringToFront();
view.invalidate();
}
Unless there are any drawbacks you encountered using the above methods.
Basically what the title says. Currently if the orientation changes in my app the ball resets back to the top of the game, however I wish to change my code so that if the user changes orientation of the device the ball and racket stay in the same spot. How would I achieve this? Would I place my entire in these two methods?
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.v(TAG, "onSaveInstanceState");
}
and
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.v(TAG, "onRestoreInstanceState");
}
(note I have already initialized the constants for TAG, within my code not seen here).
(it's also an activity)
You could the save the position of the ball and racket in the outstate so in the activity:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//If it is an integer
outState.putInt(TAG, mBallPosition);
//Or use a serializable if you wish to store an actual object
outState.putSerializable(TAG, mBallPosition);
}
Then in your onCreate method you can restore the states :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
int position = savedInstanceState.getInt(TAG,0);
//set ball position
//or get the object back using outstate.getSerializable(TAG)
}
}
I have a problem with getting the size of ImageView in an android app I'm making. I've read several solutions to this problem and none of them seem to solve my problem. I just want to get the size once at the beginning of the application like in onCreate() before loading anything to the ImageView (When it's empty.) and use it for the rest of my app.
The solution that almost works is the one with getViewTreeObserver().addOnGlobalLayoutListener.
I did that and it is getting me the right size and everything but only in the onGlobalLayout() method. All I want to do is to save that size in some class global variable but everything that happens in onGlobalLayout() stays there. It's like it has no effect on the rest of the class. I can't really write my whole application in that method it's ridiculous. Why is it happening and how can I fix that?
Also I tried the OnFocusChangeListener solution and it gives me the size only if I try to exit the app. As expected the focus is changed but this is not what I need.
Here is the code:
public class Fractaler extends Activity {
int finalWidth;
int finalHeight;
TextView txt;
ImageView fractal;
Fractal mandelbrot;
boolean viewIsMeasured = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initialize();
}
private void initialize() {
txt = (TextView) findViewById(R.id.txt);
fractal = (ImageView) findViewById(R.id.mainImage);
fractal.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!viewIsMeasured) {
finalWidth=fractal.getWidth();
finalHeight=fractal.getHeight();
viewIsMeasured = true;
mandelbrot=new Fractal("Mandelbrot",finalWidth,finalHeight);
fractal.setImageBitmap(mandelbrot.create());
}
}
});
txt.setTextColor(Color.CYAN);
//txt.setText(String.valueOf(mandelbrot.getWidth())+" "+String.valueOf(mandelbrot.getHeight()));
}
#Override
protected void onStart() {
super.onStart();
}
}