I have a ScrollView with a TextView inside of it. I want to make sure that the app automatically scrolls down to the bottom each time text is entered into the TextView.
<ScrollView
android:id="#+id/textScroll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/gridLayout"
android:layout_marginBottom="100dp"
android:fillViewport="true">
<TextView
android:id="#+id/numerTV"
android:layout_width="match_parent"
android:layout_height="70dp"
android:textSize="60sp"/>
</ScrollView>
So this is the .xml file. I have tried a lot of different solutions that I've found around here:
textScroll.post(new Runnable() {
#Override
public void run() {
textScroll.scrollTo(0, textScroll.getBottom());
//textScroll.post(new Runnable() {
//public void run() {
// textScroll.fullScroll(View.FOCUS_DOWN);
// }
// });
Log.d("Scroll","Scrolling");
}
});
Also tried to set autoscroll via xml but nothing works.
Any ideas what I'm doing wrong? How come the "solution" above works for so many but not for me?
Help much appreciated!
You can make your ScrollView move to the last position by using smoothScrollTo(x,y).
Then, you can get the arguments from the ScrollView
ScrollView sv = (ScrollView) findViewById(R.id.textScroll);
sv.smoothScrollTo(sv.getX(), sv.getY());
Related
I'm working on a project where I have a ScrollView which contains a linearlayout.
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#9e9e9e"
android:layout_weight="2"
android:id="#+id/scrollview_llChatContainer"
android:layout_above="#+id/relativeLayout">
<LinearLayout
android:id="#+id/llChatContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:background="#cccccc">
</LinearLayout>
</ScrollView>
I'm inflating this linearlayout in my code. The last result looks more like a listView. Here is how I'm inflating the LinearLayout.
public void populateMessages(List<Message> messagesList){
inflater.inflate(R.layout.inc_message_layout, llChatContainer, false);
imageLoader.displayImage(message.imageuser, (ImageView)messageLayout.findViewById(R.id.imageView));
}
if(!message.image.equalsIgnoreCase("")){
imageLoader.displayImage(message.image, (ImageView)messageLayout.findViewById(R.id.rivMsgImageN));
}
TextView tv = (TextView)messageLayout.findViewById(R.id.tvMsgTextN);
tv.setText(message.text);
llChatContainer.addView(messageLayout);
}
}
Now when the list is populated, I want the scrollView to scroll to the bottom of the LinearLayout. I have tried two of the ways I found.
scroller.post(new Runnable() {
public void run() {
scroller.fullScroll(ScrollView.FOCUS_DOWN);
}
});
scroller.post(new Runnable() {
public void run() {
scroller.scrollTo(0,scroller.getBottom());
}
});
None of the above mentioned solution is working for me. Linearlayout gets populated as expected but the scrollview doesn't even scroll a bit.
Is there any other work-around to get this done?
Thanks.
this is caused by time problem , try to scroll with a little delay , use this code
scroller.postDelayed(new Runnable() {
public void run() {
scroller.fullScroll(ScrollView.FOCUS_DOWN);
}
}, 10L);
Use scroller.scrollTo(0,linearlayout.getBottom()); or scroller.scrollTo(0,linearlayout.getHeight()); after populateMessages() called. Child of the ScrollView is changing it's value not the ScrollView itself.
What i want in pictures:
On the words: i want to disable scrolling with formatting text inside HorizontalScrollView.
Part of XML:
<ScrollView
android:id="#+id/review_scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="horizontal"
android:fillViewport="true"
android:layout_marginTop="10dp">
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tt_review_content"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Some long text"
android:scrollHorizontally="true"/>
</HorizontalScrollView>
</ScrollView>
Method(doesn't works):
private void setTtAreaWrapContent(boolean value) {
ViewGroup.LayoutParams params = textField.getLayoutParams();
if(value) { // Wrap content
textField.setWidth(scrollView.getWidth());
} else { // Scroll
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
textField.setLayoutParams(params);
}
There is a very simple way to do this.
Check if the user wants to scroll or not and then store it in a boolean variable, shouldScroll.
Now do this in onCreate,
HorziontalScrollView scrollView= (HorizontalScrollView)findViewById(R.id.scrollView);
if(!shouldScroll)
scrollView.setOnTouchListener(new OnTouch());
You also need to define a class OnTouch extending the OnTouchListener
private class OnTouch implements OnTouchListener
{
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
}
Now for the TextView formatting, just use android:singleLine="false" or use android:width="0dip"
I had absolutely the same need for code, so I initially proposed a ViewSwitcher with the same layouts, but one with HorizontalScrollView and one without it. And switch to the corresponding view depending on the setting.
However, I found an easier solution. After recreation of the Activity (when wrapping settings are changed by the user), use the code in the onCreate methode:
if (isWrapContent)
{
View mTV = findViewById(R.id.my_text_view);
HorizontalScrollView myHSV = (HorizontalScrollView) findViewById(R.id.my_hsv);
ViewGroup parent = (ViewGroup) myHSV.getParent();
ViewGroup.LayoutParams params = myHSV.getLayoutParams();
int index = parent.indexOfChild(myHSV);
myHSV.removeAllViews();
parent.removeView(myHSV);
parent.addView(mTV, index, params);
}
You need to use your id's and variables correspondingly.
It will remove the horizontal scrollview with the embedded textview and then reinsert the textview.
My answer provides direct and valid answer on how the asked issue could be resolved instead of freezing the horizontal scrollview or wondering about the point of the question, as it is done in the other comments and answers.
I'm using the setOnTouchlistner class for detecting left and right swipes. I can get it to work fine on a listview, but the listview is too small to get a good swipe every time.
I then tried to set the swipe to the main LinearLayout. I have three other LinearLayout inside this. But it is not working thanks for any help.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:baselineAligned="false"
android:orientation="horizontal"
android:id="#+id/driveView"
android:focusableInTouchMode="true"
android:focusable="true"
android:clickable="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
Here is the code:
private LinearLayout myView = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drive);
myView = (LinearLayout)findViewById(R.id.driveView);
myView.setOnTouchListener(new OnSwipeTouchListener(mContext) {
#Override
public void onSwipeLeft() {
showdrivedialog(mContext, "Drive List", "Change to Ascending list!");
}
public void onSwipeRight() {
showdrivedialog(mContext, "Drive List", "Change to Descending list!");
}
});
Two matters I want to mention.
1) I don't know about OnSwipeTouchListener but I got interested. I suspect android:clickable="true" should be false because there seems to be a conflict between swiping and clicking.
2) Look at this SO link # How to handle right to left swipe gestures. I don't know where you got the OnSwipeTouchListener class but you can copy the one with 274 votes!
Personally I did not use this class. I have used and extended HorizontalScrollView.
I have this layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.components.game.GameView
android:id="#+id/game_id"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:id="#+id/ChatLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="invisible"
android:focusable="true"
android:focusableInTouchMode="true" >
<Button
android:id="#+id/ChatCancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="X" />
<Button
android:id="#+id/ChatOkButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="OK" />
<EditText
android:id="#+id/ChatEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#+id/ChatOkButton"
android:layout_toRightOf="#+id/ChatCancelButton"
android:maxLength="50"
android:singleLine="true" />
</RelativeLayout>
</RelativeLayout>
It's a RelativeLayout over a canvas. At start time it's invisible but when a user clicks a button the layout should become visible.
The problem is that it's not becoming visible. The layout is there but it's just not drawing it. If I press the position where the layout should appear it receives the event and opens the keyboard but it's not drawing the whole layout.
What is the problem?
If I set the RelativeLayout to visible at the beginning it works fine. it shows the layout and if I toggle between invisible and visible it works fine.
I made a workaround that almost always works.
I start the layout visible and than do that in the oncreate:
chatLayout.postDelayed(new Runnable() {
#Override
public void run() {
chatLayout.setVisibility(View.INVISIBLE);
}
}, 50);
But I don't like it and want to understand what's the problem.
The code:
It starts from a canvas button which send a message to a handler:
public void showInputLayout() {
Message.obtain(gameHandler, SHOW_INPUT_LAYOUT).sendToTarget();
}
In the handler:
case SHOW_INPUT_LAYOUT:
gameActivity.setChatVisibility(true);
break;
setChatVisibility:
public void setChatVisibility(boolean isVisible) {
int visible = isVisible ? View.VISIBLE : View.INVISIBLE;
chatLayout.setVisibility(visible);
if(isVisible){
chatEditText.setFocusable(true);
chatEditText.requestFocus();
}
}
Add a click listener to RelativeLayout and switch the visibility between GONE and VISIBLE. Try something like this:
int visibility = View.VISIBLE;
RelativeLayout layout = (RelativeLayout)findViewById(R.id.ChatLayout);
layout.setVisibility(visibility);
layout.setOnClickListener(new View.OnClickListener{
public void onClick(View v)
{
if(visibility == View.VISIBLE)
visibility = View.GONE;
else
visibility = View.VISIBLE;
v.setVisibility(visibility);
}
})
I ran into a similar issue recently, and for my case the problem was actually in the onDraw() method of the view underneath (should be com.components.game.GameView in your case). See if you can add calls to Canvas' getSaveCount(), save() and restoreToCount() in your drawing code, similar to this:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int saveCount = canvas.getSaveCount();
canvas.save();
// custom drawing code here ...
// use Region.Op.INTERSECT for adding clipping regions
canvas.restoreToCount(saveCount);
}
I believe what happened was that sometimes the framework set the clipping regions for the elements on top of our Canvas-drawing widget before our onDraw() method is called so we need to make sure that those regions are preserved.
Hope this helps.
I am using a HorizentalScrollView in a view. I add TextView at runtime. I use horView.smoothScrollTo(x,y); It works fine for simulator. But it doesn't scroll at HTCDesire 2.2 ? any idea? here my code.
horView.smoothScrollTo(num, 0);
<HorizontalScrollView
android:id="#+id/cate_head"
android:scrollbars="none"
android:foregroundGravity="fill_horizontal"
android:layout_width="fill_parent"
android:paddingTop="6dip"
android:background="#drawable/slider_background"
android:focusable="true"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/cate_head_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip">
</LinearLayout>
</HorizontalScrollView>
At the end I found solution. I was calling smoothScrollTo(x,y) at the end of on create.(where else I can put that?) problem was that at the time of initializing there was not size or length found(But it should not be, because I have put all the data in that).
So call postDealy() with a delay of 50 sec. It works for me. Here is that. I put it at the end of onCreate();
May b anyone else have a batter solution...
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
horView.smoothScrollTo((scrollAmount), 0);
}
}, 50);
You can use View.post to avoid depending on timing.
horView.post(new Runnable() {
public void run() {
horView.smoothScrollTo((scrollAmount), 0);
}
});
This gets executed right after the view has been attached to the screen.