Scrolling a ScrollView to a specific id - java

I have a Scrollview in my activity , I want when I press a button the view scrolls down to a specific ID in the view. After some search here I found I can use this code
scrollView.post(new Runnable() {
#Override
public void run() {
scrollView.fullScroll(View.FOCUS_DOWN);
}
});
but it scrolls all the page down. I want to scroll to a specific ID in the middle of the view

ScrollView scrollView = (ScrollView) findViewById(R.id.scroll_view);
scrollView.postDelayed(new Runnable() {
public void run() {
scrollView.scrollTo(0, (int)view.getY());
}
}, 100);
view = your view you want to scroll to

You can do this as below:
private void smartScrollToPosition(ListView listView, int desiredPosition) {
//Write your logic here.
listView.smoothScrollToPosition(desiredPosition);
}
On button handler you can call this as follows
ListView listView = (ListView) findViewById(R.id.lessonsListView);
smartScrollToPosition(listView, 0); // scroll to top
return true;

Related

Access a certain button from recyclerview and change it's background image

I'm trying to change the background image of a certain button when clicked in a recyclerView. The button's background image is changing properly but also changing the background of the button found in the 8th..16th..etc row as well. (I am currently populating data in the recycler view using a for-loop for testing)
My code is
#Override
public void onBindViewHolder(final myFirstAdapter.ViewHolder holder, int position) {
firstlistitem listItem = listItems.get(position);
holder.itemView.setTag(position);
holder.btnBookMark.setTag(position);
holder.btnBookMark.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.btnBookMark.setBackgroundResource(R.drawable.bookmarkred);
}
});
}
The background is changing because, its a RecyclerView and it recyclers the view and reuses it. Hence, when you click on 8th position and scroll to bottom, it is reusing the item at 8 position with custom background for other items. Because of this you are getting custom background for later items on scroll.
If you have many items which will have changed background do this.
class ViewHolder extends RecyclerView.ViewHolder{
boolean newBackground = false;
Button button
ViewHolder(View itemView){
...
button.setOnClickListner((v) - > newBackground = true);
}
}
Then you can check the value of newBackground and set the background in onBindViewHolder()
If you have only one item of which the background will change at a time then you can declare a field in the Adapter and check that to change the background.
class MyAdapter extends RecyclerView.Adapter<ViewHolder>{
int newBackgroundPos = -1;
#Override
public final void onBindViewHolder(ViewHolder holder, int position) {
holder.button.setOnClickListener((v) -> newBackGroundPos = position);
if(position == newBackgroundPos)
holder.itemView.setBackground(newBackground);
else
holder.itemView.setBackground(normalBackground);
}
}

Show BottomSheet after change the layout

I have a BottomSheet "buttomSheet" (in this sheet it is a list view that is GONE) and a normal Button "btnShowListView" (out from the "buttomSheet").
I want that when I click on "btnShowListView" the list view in the bottomSheet will be Visible its work but only after 2 clicks on button "btnShowListView"...
this is my code:
final View bottomSheetView = findViewById(R.id.bottomSheetLayout);
listView = (ListView) bottomSheet.findViewById(R.id.listView);
buttomSheet = BottomSheetBehavior.from(bottomSheetView);
btnShowListView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listView.setVisibility(View.VISIBLE);
bottomSheetView.requestLayout();
bottomSheetView.invalidate();
bottomSheet.setState(BottomSheetBehavior.STATE_EXPANDED);
}
});
You can make the listview already visible, there's no need to hide it; you can get te same effect by setting the state of the bottom sheet behavior to HIDDEN.
I tested the code below and it should work also for you.
final View bottomSheetView = findViewById(R.id.bottomSheetLayout);
bottomSheetBehavior= BottomSheetBehavior.from(bottomSheetView);
bottomSheetBehavior.setHideable(true);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
btnShowListView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
bottomSheet.setState(BottomSheetBehavior.STATE_EXPANDED);
}
});

Resizing Views before drawing

In my layout I have a GridView containing 4 custom ImageViews. I'm setting GridView's visibility to invisible until all ImageViews are resized at first but when the GridView is shown, there's a short blink with ImageViews still unchanged.
blink for a split second
views are resized in a moment
Each ImageView creates separate listener in order to scale its size:
//Setting new params as half of parent's size and increasing counter
if (getViewTreeObserver().isAlive()) {
final ViewTreeObserver viewTreeObserver = getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
View parent = (View) getParent();
int dimension = Math.min(parent.getWidth(), parent.getHeight()) / 2;
mThisImageView.setLayoutParams(new AbsListView.LayoutParams(dimension, dimension));
ResizeCounter.setCounter(ResizeCounter.getCounter() + 1);
return true;
}
});
}
//Activity listens to the moment when all ImageViews have been resized
ResizeCounter.addCounterListener(new OnResizeCounterChangeListener() {
#Override
public void onResizeCounterChanged() {
if (ResizeCounter.getCounter() == 4) {
mAnswerGridView.setVisibility(View.VISIBLE);
}
}
});
I've also tried to resize them in onGlobalLayout method (same result) and to override onMeasure method (parent View is still null at this point).
I suspect that it's too late to change views in onPreDraw() but is there a method that can be called earlier inside which I can be sure that all views have been measured?
Try to call mAnswerGridView.requestLayout() before mAnswerGridView.setVisibility(View.VISIBLE);
This may not work because as it's stated at Android Developers
This will schedule a layout pass of the view tree.
So you may better force relayout:
relayoutChildren(View view) {
view.measure(
View.MeasureSpec.makeMeasureSpec(view.getMeasuredWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(view.getMeasuredHeight(), View.MeasureSpec.EXACTLY));
view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); }
I've created a handler that schedules setting visibility right after calling requestLayout.
Works well in this case.
ResizeCounter.addCounterListener(new OnResizeCounterChangeListener() {
#Override
public void onResizeCounterChanged() {
if (ResizeCounter.getCounter() == 4) {
mAnswerGridView.requestLayout();
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
mAnswerGridView.setVisibility(View.VISIBLE);
}
});
}
}
});

How can I remove setBackgroundResource when new View is clicked?

I have a Horizontal Listview with a textview. When I click on a textview in the view, that particular textview gets a border.
public View getView(int position, View convertView, ViewGroup parent) {
View retval = LayoutInflater.from(parent.getContext()).inflate(R.layout.minute_listview, null);
Typeface afBold = Typeface.createFromAsset(getAssets(), "fonts/AftenScreen-Bold.ttf");
minuteText = (TextView) retval.findViewById(R.id.title);
Button button = (Button) retval.findViewById(R.id.clickbutton);
button.setOnClickListener(mOnButtonClicked);
minuteText.setText(dataObjects[position]);
minuteText.setTypeface(afBold);
//THIS IS WHERE THE BORDER GETS SET
minuteText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.setBackgroundResource(R.drawable.border);
}
});
return retval;
}
Now, how can I remove this border and set it on the next textview thats clicked?
Use this it will give you a white background or a translucent one, in other words it has been removed
WhatEverView.setBackground(new ColorDrawable(Color.TRANSPARENT));
okay full code
int pos -1;// default is -1, which means no one has altered it
// replicate this onclick listener logic
minuteText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(pos != -1){ // it is not -1 that means some1 has altered it
parentView.findViewById(pos).
setBackground(new ColorDrawable(Color.TRANSPARENT));
// the above line searched for the view and changed the background
}
pos = v.getId(); // the id of the new view, keep doing it
v.setBackgroundResource(R.drawable.border);
}
});
so use this for all onclick listeners you want that effect on
Does it fit your requirement?
add this
TextView ClicledTv ;//to save the clicked tv id
then
minuteText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(Clickedtv!=null)
clickedtv.setBackground(R.drawable.anotherOne);
v.setBackgroundResource(R.drawable.border);
clickedTv=minuteText;
}
});

Can I scroll a ScrollView programmatically in Android?

Is there any way to scroll a ScrollView programmatically to a certain position?
I have created dynamic TableLayout which is placed in a ScrollView. So I want that on a specific action (like clicking a Button, etc.) the particular row should scroll automatically to a top position.
Is it possible?
The answer from Pragna does not work always, try this:
mScrollView.post(new Runnable() {
public void run() {
mScrollView.scrollTo(0, mScrollView.getBottom());
}
});
or
mScrollView.post(new Runnable() {
public void run() {
mScrollView.fullScroll(mScrollView.FOCUS_DOWN);
}
});
if You want to scroll to start
mScrollView.post(new Runnable() {
public void run() {
mScrollView.fullScroll(mScrollView.FOCUS_UP);
}
});
ScrollView sv = (ScrollView)findViewById(R.id.scrl);
sv.scrollTo(0, sv.getBottom());
or
sv.scrollTo(5, 10);
I wanted the scrollView to scroll directly after onCreateView() (not after e.g. a button click). To get it to work I needed to use a ViewTreeObserver:
mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mScrollView.post(new Runnable() {
public void run() {
mScrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
});
But beware that this will be called everytime something gets layouted (e.g if you set a view invisible or similar) so don't forget to remove this listener if you don't need it anymore with:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) on SDK Lvl < 16
or
public void removeOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) in SDK Lvl >= 16
There are a lot of good answers here, but I only want to add one thing. It sometimes happens that you want to scroll your ScrollView to a specific view of the layout, instead of a full scroll to the top or the bottom.
A simple example: in a registration form, if the user tap the "Signup" button when a edit text of the form is not filled, you want to scroll to that specific edit text to tell the user that he must fill that field.
In that case, you can do something like that:
scrollView.post(new Runnable() {
public void run() {
scrollView.scrollTo(0, editText.getBottom());
}
});
or, if you want a smooth scroll instead of an instant scroll:
scrollView.post(new Runnable() {
public void run() {
scrollView.smoothScrollTo(0, editText.getBottom());
}
});
Obviously you can use any type of view instead of Edit Text. Note that getBottom() returns the coordinates of the view based on its parent layout, so all the views used inside the ScrollView should have only a parent (for example a Linear Layout).
If you have multiple parents inside the child of the ScrollView, the only solution i've found is to call requestChildFocus on the parent view:
editText.getParent().requestChildFocus(editText, editText);
but in this case you cannot have a smooth scroll.
I hope this answer can help someone with the same problem.
Use something like this:
mScrollView.scrollBy(10, 10);
or
mScrollView.scrollTo(10, 10);
Try using scrollTo method More Info
If you want to scroll instantly then you can use :
ScrollView scroll= (ScrollView)findViewById(R.id.scroll);
scroll.scrollTo(0, scroll.getBottom());
OR
scroll.fullScroll(View.FOCUS_DOWN);
OR
scroll.post(new Runnable() {
#Override
public void run() {
scroll.fullScroll(View.FOCUS_DOWN);
}
});
Or if you want to scroll smoothly and slowly so you can use this:
private void sendScroll(){
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
try {Thread.sleep(100);} catch (InterruptedException e) {}
handler.post(new Runnable() {
#Override
public void run() {
scrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
}).start();
}
**to scroll up to desired height. I have come up with some good solution **
scrollView.postDelayed(new Runnable() {
#Override
public void run() {
scrollView.scrollBy(0, childView.getHeight());
}
}, 100);
Yes, you can.
Let's say you got one Layout and inside that, you got many Views. So if you want to scroll to any View programmatically, you have to write the following code snippet:
For example:
content_main.xml
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txtView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
MainActivity.java
ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
Button btn = (Button) findViewById(R.id.ivEventBanner);
TextView txtView = (TextView) findViewById(R.id.ivEditBannerImage);
If you want to scroll to a specific View, let's say txtview, in this case, just write:
scrollView.smoothScrollTo(txtView.getScrollX(),txtView.getScrollY());
And you are done.
I got this to work to scroll to the bottom of a ScrollView (with a TextView inside):
(I put this on a method that updates the TextView)
final ScrollView myScrollView = (ScrollView) findViewById(R.id.myScroller);
myScrollView.post(new Runnable() {
public void run() {
myScrollView.fullScroll(View.FOCUS_DOWN);
}
});
Note: if you already in a thread, you have to make a new post thread, or it's not scroll new long height till the full end (for me).
For ex:
void LogMe(final String s){
runOnUiThread(new Runnable() {
public void run() {
connectionLog.setText(connectionLog.getText() + "\n" + s);
final ScrollView sv = (ScrollView)connectLayout.findViewById(R.id.scrollView);
sv.post(new Runnable() {
public void run() {
sv.fullScroll(sv.FOCUS_DOWN);
/*
sv.scrollTo(0,sv.getBottom());
sv.scrollBy(0,sv.getHeight());*/
}
});
}
});
}
Adding another answer that does not involve coordinates.
This will bring your desired view to focus (but not to the top position) :
yourView.getParent().requestChildFocus(yourView,yourView);
public void RequestChildFocus (View child, View focused)
child - The child of this ViewParent that wants focus. This view will contain the focused view. It is not necessarily the view that actually has focus.
focused - The view that is a descendant of child that actually has focus
Everyone is posting such complicated answers.
I found an easy answer, for scrolling to the bottom, nicely:
final ScrollView myScroller = (ScrollView) findViewById(R.id.myScrollerView);
// Scroll views can only have 1 child, so get the first child's bottom,
// which should be the full size of the whole content inside the ScrollView
myScroller.smoothScrollTo( 0, myScroller.getChildAt( 0 ).getBottom() );
And, if necessary, you can put the second line of code, above, into a runnable:
myScroller.post( new Runnable() {
#Override
public void run() {
myScroller.smoothScrollTo( 0, myScroller.getChildAt( 0 ).getBottom() );
}
}
It took me much research and playing around to find this simple solution. I hope it helps you, too! :)
just page scroll:
ScrollView sv = (ScrollView) findViewById(your_scroll_view);
sv.pageScroll(View.FOCUS_DOWN);
I was using the Runnable with sv.fullScroll(View.FOCUS_DOWN);
It works perfectly for the immediate problem, but that method makes ScrollView take the Focus from the entire screen, if you make that AutoScroll to happen every time, no EditText will be able to receive information from the user, my solution was use a different code under the runnable:
sv.scrollTo(0, sv.getBottom() + sv.getScrollY());
making the same without losing focus on important views
greetings.
it's working for me
mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mScrollView.post(new Runnable() {
public void run() {
mScrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
});
private int totalHeight = 0;
ViewTreeObserver ScrollTr = loutMain.getViewTreeObserver();
ScrollTr.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
loutMain.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
loutMain.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
TotalHeight = loutMain.getMeasuredHeight();
}
});
scrollMain.smoothScrollTo(0, totalHeight);
I had to create Interface
public interface ScrollViewListener {
void onScrollChanged(ScrollViewExt scrollView,
int x, int y, int oldx, int oldy);
}
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
public class CustomScrollView extends ScrollView {
private ScrollViewListener scrollViewListener = null;
public ScrollViewExt(Context context) {
super(context);
}
public CustomScrollView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomScrollView (Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, l, t, oldl, oldt);
}
}
}
<"Your Package name ".CustomScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true"
android:scrollbars="vertical">
private CustomScrollView scrollView;
scrollView = (CustomScrollView)mView.findViewById(R.id.scrollView);
scrollView.setScrollViewListener(this);
#Override
public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) {
// We take the last son in the scrollview
View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1);
int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));
// if diff is zero, then the bottom has been reached
if (diff == 0) {
// do stuff
//TODO keshav gers
pausePlayer();
videoFullScreenPlayer.setVisibility(View.GONE);
}
}

Categories

Resources