I have an Android program with a ScrollView that will correctly do an automatic scroll when I call the scrollBy method on the emulator on my computer but will not do it on my Android phone.
Here is the code:
public class RecordGameActivity3 extends Activity {
ScrollView myView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recordgame3);
myView = (ScrollView)findViewById(R.id.scrollView1);
}
public void addPlayer(View v)
{
//Removed non-related code
myView.smoothScrollBy(0, 50);
}
}
Also, the regular scrollBy method doesn't work or the scrollTo method (although I may just not be using that correctly since that doesn't work on the computer either). Does anyone have an idea what might be wrong?
EDIT:
My problem as Darrell's answer showed me was that I was calling my smoothScrollBy method from within a function where I was making changes to the layout that would make the scroll area big enough to be able to be scrolled. Apparently, by the time I was calling it in the function, the changes weren't actually applied and so it couldn't be scrolled.
Thus, I changed the code using his advice to the following:
public class RecordGameActivity3 extends Activity {
ScrollView myView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recordgame3);
myView = (ScrollView)findViewById(R.id.scrollView1);
// New code that listens for a change in the scrollView and then calls the scrollBy method.
ViewTreeObserver vto = myView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
myView.smoothScrollBy(0, 100);
}});
}
public void addPlayer(View v)
{
//Code that is called on an onClick listener that adds things to the ScrollView making it scrollable.
}
}
Are you calling smoothScrollBy from the onCreate method? Try waiting until after the views are set up, for instance from onResume. (If you must do it from onCreate you could register a ViewTreeObserver for your view with a OnGlobalLayoutListener, and do the scrolling from there.)
In my case, I need to scroll the ScrollView when there is a MotionEvent.ACTION_UP event triggered in the exact ScrollView , scrollTo() works, but smoothScrollTo() doesn't . Thanks to you guys, I figured it out now, use a handler to smoothScroll the view after a while will work.
Related
im trying to measure a ImageView, after my fragment is displayed, or if possible before.
I heared, that its not yet possible in the onActivityCreated. But somehow it works with the global Layout listener. -But how? -I have a method, wich measures and does some code, i just don't know when to call the method.
Can somebody gice an example?
the beginning of the measure method:
public void skalierung() {
InputStream dots=getResources().openRawResource(R.drawable.amountofdots);
Bitmap dotsBmp = BitmapFactory.decodeStream(dots);
View mainframe=(View)getActivity().findViewById(R.id.mainframe);
int breite=mainframe.getWidth();
Thanks!
To set a GlobalLayoutListener you have to get ViewTreeObserverof your View using the view.getViewTreeObserver() method which :
Returns the ViewTreeObserver for this view's hierarchy. The view tree observer can be used to get notifications when global events, like layout, happen.
After doing that well , you can addOnGlobalLayoutListener on your ViewTreeObserever
OnGlobalLayoutListener : Interface definition for a callback to be invoked when the global layout state or the visibility of views within the view tree changes.
and inside the onGlobalLayoutmethod you can call the getWidth on the your desired view, here's an example :
View mainframe=(View)getActivity().findViewById(R.id.mainframe);
ViewTreeObserver vto = mainframe.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
skalierung(); // here you can call the getWidth and getHeight methods
ViewTreeObserver obs = mainframe.getViewTreeObserver();
// you have to reset the ViewTreeObserver each time to ensure the reuse of the OnGlobalLayoutListener
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
obs.removeOnGlobalLayoutListener(this);
} else {
obs.removeGlobalOnLayoutListener(this);
}
}
});
Hope it helps.
I have problem with getting information about views after calling setContentView(). I'm changing layout of activity after click on button. Here is the example of my code.
public void onClickButton1(View v) {
setContentView(R.layout.activity_main);
setScreen();
}
But durring execution setScreen() method, layout still is not rendered, so I cannot call getWidth() on some view intended in layout (respectively I can but I always get 0). How I can wait until setContentView() is finished? Please notice that using of this:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
setScreen();
}
is not sufficient for me. I need to change layout independently on activity cycle.
You need to attach a ViewTreeObserver to your layout:
setContentView(R.layout.yourLayoutName);
View yourLayout = findViewById(R.id.ID_OF_YOUR_LAYOUT);
ViewTreeObserver vto = yourLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//Do your work
vto.removeOnGlobalLayoutListener(this);
}
});
There's no easy way to use setContentView() to get the result you want. You either need to entirely remove all views and then inflate the new layout, use a ViewFlipper to switch between different views, or, which is IMHO the best approach, rework your app to use Fragments
I'm getting height and width of a view, inflated in the getView() method. It's a grid item.
Usually I use post() on the view to get the size, after it was attached to the layout. But it returns 0.
final View convertViewFinal = convertView;
convertView.post(new Runnable() {
#Override
public void run() {
doSomethingWithConvertView(convertViewFinal);
}
});
...
doSomethingWithConvertView(View v) {v.getWidth(); /*returns 0*/};
How do I get the size?
While using a viewTreeObserver definitely works, I have found that calling measurements requirements on inflated views can be done reliably using a runnable from the activity's view. i.e.
someActivityInstance.getWindow().getDecorView().post(new Runnable() {
#override
public void run() {
// someMeasurements
}
});
The thing is that convertview most likely is not drawn on the phone screen yet, so you have to wait until it is ready.
You need to use a ViewTreeObserver, to know exactly when the view has been drawn.
Check this answer for more info:
When Can I First Measure a View?
You probably is calling this at onCreate or onStart or onResume, methods which runs before layout measure.
But there is a lot of work arounds, this is one good option:
ViewTreeObserver vto = rootView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
v.getWidth();//already measured...
}
});
Where rootView may be any viewGroup in a higher level than the one you want the width.
But be aware that this listner may run more than once.
Would it be possible to hide a view off the top edge of the screen, and only have it appear if the user scrolls upwards?
My first attempt used a scrollview, but it seems that scrollTo() doesn't work unless I used postDelayed (it doesn't even work with Post()). I tried adding it to the scrollview's view tree observer onPreDraw() event and it still doesn't work unless I delay it, so there is an ugly glitch when the activity is first launched.
The second issue is that if the onscreen keyboard is minimized, the view no longer needs to scroll so hiding things by using a scroll offset no longer works. I thought about manipulating the height in code, but this seems pretty hackish.
Is there a better way to do this than by using a scrollview? Alternatively, Does anyone have any tips on the best place to place the scrollTo (the end of onCreate does not work nor the other places I have tried) so I don't need to use postDelayed? That would at least eliminate one glitch.
Thanks!
This is the code I'm using right now, which is the least glitchy but I don't understand why it doesn't work until the third time onPreDraw() is called.
mScrollView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
#Override
public boolean onPreDraw()
{
final int fieldYStart = mFieldIWantAtTheTop.getTop();
if (mFieldIWantAtTheTopYStart != fieldYStart
|| mScrollView.getScrollY() < 10)
{
mFieldIWantAtTheTopYStart = fieldYStart;
mScrollView.post(new Runnable()
{
#Override
public void run()
{
Log.v("Testing", "scrolling!");
mScrollView.scrollTo(0, mFieldIWantAtTheTopYStart);
Log.v("Testing", "scroll is now=" + mScrollView.getScrollY());
}
});
}
return true;
}
});
I also tried using a custom scrollview as mentioned below, but this does not solve the issue of the graphical glitch:
#Override
public void onMeasure(int measureWidthSpec, int measureHeightSpec) {
super.onMeasure(measureWidthSpec, measureHeightSpec);
Log.v("Testing", "Scrolling");
post(
new Runnable()
{
public void run()
{
scrollTo(0, 100);
Log.v("Testing", "ScrollY = " + getScrollY());
}
});
}
This code works as does the onPreDraw() code above but there is still a glitch when the activity is launched because the activity is first drawn with the scroll at 0.
I haven't tried this, but you may want to create a custom ScrollView and override onMeasure:
ScrollView scroll = new ScrollView(this) {
#Override
public void onMeasure(int measureWidthSpec, int measureHeightSpec) {
super.onMeasure(measureWidthSpec, measureHeightSpec);
scrollTo(...);
}
};
It seems like this would be the earliest point that scrollTo would be valid.
Edit - I found this answer, which apparently worked for the asker. Is this the method you tried?
I have created one custom view that contains the horizontalscrollview. Now when i changes the orientation its scroll state change to 0 every time.
I got the previous scroll state by using onSaveInstanceState(Bundle savedInstanceState) and onRestoreInstanceState(Bundle savedInstanceState) . in onRestoreInstanceState i am using following method to get reposition the scroll,
hoz_scroll.scrollTo(hoz_x_pos, hoz_scroll.getScrollY());
But there is not effect at all.
Help appreciated. Thanks.
If you have to call onCreate every time orientation change the position resets.
You can avoid it by adding orientation changed to manifest but not sure if current scroll state is intact.
I have researched it couple of days ago.If your interface has stadar dimentions on every orientation then you might find an equation by sampling many scroll values.
Create a map with the getScrollY() with values on landscape and portait that displays the same text. More values are better. Then use Polynomial interpolation to create a polynomial equation using matlab or papper.
More values -> more accuracy
http://en.wikipedia.org/wiki/Polynomial_interpolation
also scrolling to a position must be done like this
hoz_scroll.post(new Runnable() {
public void run() {
scroller.scrollTo(hoz_x_pos,hoz_scroll.getScrollY());
}
});
I believe you need to set
android:configChanges="orientation"
in your activity's element in AndroidManifest.xml.
Then you need to override public void onConfigurationChanged(Configuration config) in your activity.
Put this code in your Activity to not have it scroll when orientation changes. You don't even need to code.
#Override
public void onConfigurationChanged(Configuration config){
super.onConfigurationChanged(config);
}
here is a working solution:
private ScrollView scroll;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content);
TextView title=(TextView) findViewById(R.id.textView1);
TextView content=(TextView) findViewById(R.id.textView2);
title.setText(getIntent().getStringExtra("title"));
content.setText(getIntent().getStringExtra("content"));
scroll = (ScrollView) findViewById(R.id.scrollView1);
if(savedInstanceState!=null){
final int y=savedInstanceState.getInt("position");
scroll.post(new Runnable() {
public void run() {
scroll.scrollTo(0,y);
}
});
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("position", scroll.getScrollY());
}