Check if a ScrollView has reached the top of the layout - java

Is it possible to check if a ScrollView is scrolled all its way in the top?
I want to check this so I can enable a SwipeRefreshLayout, otherwise keeping it disabled.
With a ListView it could be done like this, but there's no setOnScrollListener for ScrollViews
listView.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
boolean enable = false;
if(listView != null && listView.getChildCount() > 0){
// check if the first item of the list is visible
boolean firstItemVisible = listView.getFirstVisiblePosition() == 0;
// check if the top of the first item is visible
boolean topOfFirstItemVisible = listView.getChildAt(0).getTop() == 0;
// enabling or disabling the refresh layout
enable = firstItemVisible && topOfFirstItemVisible;
}
swipeRefreshLayout.setEnabled(enable);
}
});

This link might be helpful to You. It shows, how to set scroll listener for ScrollView. Then, refer to #antonio answer.
For your case it would be:
mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
int scrollY = mScrollView.getScrollY(); //for verticalScrollView
if (scrollY == 0)
swipeRefresh.setEnabled(true);
else
swipeRefresh.setEnabled(false);
}
});

You can use the getScrollY() method (from the View class)

In Kotlin:
scrollView.viewTreeObserver.addOnScrollChangedListener {
if (!scrollView.canScrollVertically(1)) {
// Bottom of scroll view.
}
if (!scrollView.canScrollVertically(-1)) {
// Top of scroll view.
}
}

Related

How to change background colour to specific viewholder items in a RecycleView?

I am trying to change background color in specific item(s) in a RecycleView.
Because I need to set text too, I have the following code that works fine:
protected void populateViewHolder(RankingViewHolder viewHolder, final Ranking model, int position)
{
final Context mContext = getActivity().getApplicationContext();
viewHolder.txt_name.setText(model.getUserName());
viewHolder.txt_score.setText(String.valueOf(model.getScore()));
viewHolder.txt_class.setText(model.getUser_class());
Picasso.with(mContext).load(model.getAvatarUrl()).error(R.drawable.ic_people_black_24dp).into(viewHolder.personPhoto);
int totalRanking = adapter.getItemCount();
int realRank = totalRanking - viewHolder.getAdapterPosition();
viewHolder.ranknumber.setText("# "+String.valueOf(realRank));
}
This works as I want and realRanktakes the correct values, and the viewHolder.ranknumber.setText("# "+String.valueOf(realRank));
Sets the right text with no problem.
Now I am trying (as I got a number/text result correct, to make an if statement like this:
if(adapter.getItemCount() -viewHolder.getAdapterPosition() == 0)
{
viewHolder.itemView.setBackgroundColor(Color.GREEN);
}
if(adapter.getItemCount() -viewHolder.getAdapterPosition() == 1)
{
viewHolder.itemView.setBackgroundColor(Color.YELLOW);
}
if(adapter.getItemCount() -viewHolder.getAdapterPosition() == 2)
{
viewHolder.itemView.setBackgroundColor(Color.BLUE);
}
(I tried with String.valueOf(realRank)equality, with realRankequality too)
In all cases I have the same result. The color changes as its should at positions 1,2,3 BUT it changes at positions 7,8,9 and 14,15,16 and 21,22,23 etc.
What am I missing here?
public class RankingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private ItemClickListener itemClickListener;
public TextView txt_name, txt_score, txt_class, ranknumber;
public ImageView personPhoto;
public RankingViewHolder(View itemView)
{
super(itemView);
txt_name = itemView.findViewById(R.id.txt_name);
txt_score = itemView.findViewById(R.id.txt_score);
personPhoto = itemView.findViewById(R.id.person_photo);
txt_class = itemView.findViewById(R.id.txt_class);
ranknumber = itemView.findViewById(R.id.ranknumber);
itemView.setOnClickListener(this);
}
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
#Override
public void onClick(View view) {
itemClickListener.onClick(view , getAdapterPosition(),false);
}
}
The adapter:
adapter = new FirebaseRecyclerAdapter<Ranking, RankingViewHolder>(
Ranking.class,
R.layout.layout_ranking,
RankingViewHolder.class,
rankingTbl.orderByChild("score").limitToFirst(100)
)
This line of code int realRank = totalRanking - viewHolder.getAdapterPosition();gives a number (1,2,3,4,5,6 etc.) Why i cannot use this number to check equality?
Notice
Keeping this code for NOT working solution, just for future reference:
if(position == 0){
viewHolder.itemView.setBackgroundColor(Color.GREEN);
}
else if(position == 1){
viewHolder.itemView.setBackgroundColor(Color.YELLOW);
}
else if(position == 2){
viewHolder.itemView.setBackgroundColor(Color.BLUE);
}
else{
viewHolder.itemView.setBackgroundColor(Color.WHITE);
}
This changes the color BUT not for only 3 first items. As you scroll down, changes the color for every 3 first viewable items like before, meaning 1,2,3, 7,8,9, etc.
Update:
I dont use a custom adapter, i use FirebaseRecyclerAdapter.
Thanks to #Muhammad Haroon comment i checked that has getItemViewType. So now i m trying with it like
position =adapter.getItemViewType( 0);
if(position == 0){
viewHolder.itemView.setBackgroundColor(Color.GREEN);
}
Not working for now, but i think its the correct direction...
Update 2
With position its not possible as RecycleView recycles the views so i have the same result. The working code is
if (linearLayoutManager.findFirstVisibleItemPosition() > 0) {
viewHolder.itemView.setBackgroundResource(R.drawable.blackframe);
}
else{
viewHolder.itemView.setBackgroundResource(R.drawable.goldframe);
}
Works fine except that after scrolling loosing the change of background.
So as we want and need the perfection, any idea for keeping even after scroll?
hi try add this in your Adapater it may solve your problem.
#Override
public int getItemViewType(int position) {
return position;
}
Please give this a try
override in your custom adapter
#Override
public long getItemId(int position) {
return position;
}
and in in your adapter object:
myAdapter.setHasStableIds(true);
In populateViewHolder add these line of code
if(position == 0){
viewHolder.itemView.setBackgroundColor(Color.GREEN);
}
else if(position == 1){
viewHolder.itemView.setBackgroundColor(Color.YELLOW);
}
else if(position == 2){
viewHolder.itemView.setBackgroundColor(Color.BLUE);
}
else{
viewHolder.itemView.setBackgroundColor(Color.WHITE);
}
position is a parameter in populateViewHolder.

ListView Scroll Direction

I need to check the direction of the scroll when my listview is scroll up or down, I am getting it as:
int lastVisibleItem = 0;
boolean isScrollingDown = false;
void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem > lastVisibleItem) {
isScrollingDown = true;
Log.e("logkey","down");
}
else {
Log.e("logkey","up");
isScrollingDown = false;
}
lastVisibleItem = firstVisibleItem;
}
The problem is when the visible items are equal to the screen or when there are items to the whole screen suppose that only 6 items fit in the screen and the last item is half visible, the log cat starts showing me the both down and up at the same time!
In simple words, in the above case, the scroll direction is ambiguous to get when there are items equal to the screen to fit in and the very last item is half visible and when I scroll I am getting this problem!
Can somebody please tell me what I am doing wrong? Thanks in advance!
Implement the listview ScrollListener
listview.setOnScrollListener(new OnScrollListener() {
private int LastVisibleItem;
#Override
public void onScrollStateChanged(AbsListView view, int scrollState)
{}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(LastVisibleItem<firstVisibleItem){
Log.d("Tag","Scroll down");
}
if(LastVisibleItem>firstVisibleItem){
Log.d("Tag","Scroll up");
}
LastVisibleItem=firstVisibleItem;
}
});
So luckily i found something great on the GitHub! I have changed my simple native ListView to Observable List View listed here
https://github.com/ksoichiro/Android-ObservableScrollView
and it worked like a charm, as i want to work it as!

I want to detect the end of scroll event [duplicate]

This question already has answers here:
Detect end of ScrollView
(13 answers)
Closed 4 years ago.
I want to detect the end of scroll event of a scrollView.
first,i implement the OnCrollChange method and i try to listen some values if they can help me to know the end of scroll.
Thank to help me.
scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener(){
#Override
public void onScrollChange(View view, int i, int i1, int i2, int i3){
Toast.makeText(getApplicationContext(),"in SCroll ------->"+i+" "+i1+" "+i2+" "+i3,Toast.LENGTH_SHORT).show();
shadowView.setBackgroundResource(R.drawable.shadow);
if ((i3==0)){
Toast.makeText(getApplicationContext()," equality ----------------------> ",Toast.LENGTH_SHORT).show();
shadowView.setBackgroundResource(R.drawable.trans);
}
else {
// Toast.makeText(getApplicationContext()," NO ----------------------> ",Toast.LENGTH_SHORT).show();
}
}
});
This will help
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
if (scrollView != null) {
if (scrollView.getChildAt(0).getBottom() <= (scrollView.getHeight() + scrollView.getScrollY())) {
//scroll view is at bottom
} else {
//scroll view is not at bottom
}
}
}
});
Modify your onScrollChanged method as below
#Override
public void onScrollChanged(View view, int i, int i1, int i2, int i3){
View view = (View) getChildAt(getChildCount()-1);
int delta = (view.getBottom()-(getHeight()+getScrollY()));
if(delta == 0){
// You have reached bottom of the scroll view
}
}
Thank to all of you.
after some testes;i see that the values int i, int i1, int i2 take the same value egual to 0 at the real time so it solve my problem.
I will not use your suggestions now but i learn some important notion from them only by reading.

view visibility check in fragment inside viewpager and tablayout in Android

I have a weird problem.
Achieved
I have 4 Fragments in a ViewPager attached with TabLayout. The first one is QR-code Scanner, which shows a camera. I wanted to start camera only when the Fragment is visible. For this, I override the Fragment's method setUserVisibleHint.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser) {
checkPermissionForCamera(); //it checks permission and start camera
} else {
stopCamera();
}
}
And it's working absolutely fine.
Desired
Now, what I want to achieve is that when Fragment is not visible (or is being visible by scrolling), it shows a view with background over camera, so that instead of camera, that cover is visible. Like image below.
For it, I edited startCamera and stopCamera, now it looks like below,
public void startCamera() {
if(cameraCover != null)
cameraCover.setVisibility(View.GONE);
isCameraStarted = true;
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
mScannerView.startCamera();
}
public void stopCamera() {
if(cameraCover != null)
cameraCover.setVisibility(View.VISIBLE);
if(mScannerView != null) {
isCameraStarted = false;
mScannerView.stopCamera();// Stop camera on pause
mScannerView.stopCameraPreview();// Stop camera preview
}
}
But the gray cover is only visible for the first time, rest of the time I get the camera opened with view on which it's scrolled, like below.
I've also tried to override onPageScrolled of OnPageChangeListener, but with no luck. Here's what I've done.
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(position == 0) {
if(positionOffset > 0.7) {
fragment = adapter.getItemAtPosition(0); //fragment is at zero
if(fragment != null) {
if(fragment instanceof ScanQRFragment) {
((ScanQRFragment) fragment).stopCamera();
}
}
}
}
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Try either of the following ways :
1- override setMenuVisibility :
#Override
public void setMenuVisibility(final boolean visible) {
if (visible) {
//start camera preview
}
super.setMenuVisibility(visible);
}
2- Check yourFragment.isResumed() instead of isVisible()

How to make an options menu for a PopupWindow?

My app has an options menu that is available in almost all Activities, which was created by implementing onCreateOptionsMenu(). But in one Activity there is a PopupWindow, and when this PopupWindow has focus (required for proper functioning) tapping the menu button does not bring up the options menu.
PopupWindows do not have an onCreateOptionsMenu() function. Is there some other way to add an options menu to a PopupWindow?
Alternatively, is there a way to get the options menu from the Activity behind it to show up when the user taps the menu button?
I solved this by intercepting the menu key and calling openOptionsMenu() on the activity. Here is the key listener:
OnKeyListener mMenuKeyListener = new OnKeyListener() {
#Override
public boolean onKey(View view, int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_MENU) {
activity.openOptionsMenu();
return true;
} else {
return false;
}
}
};
I think you have to add this key listener to every view in the PopupWindow to get it to work, so I wrote a function to do that:
public void setupMenuKeyListenerRecursive(View v) {
if (v != null) {
try {
ViewGroup viewGroup = (ViewGroup)v;
int childCount = viewGroup.getChildCount();
for (int index = 0; index < childCount; index++) {
View child = viewGroup.getChildAt(index);
setupMenuKeyListenerRecursive(child);
}
} catch (Exception e) {
}
v.setOnKeyListener(mMenuKeyListener);
}
}

Categories