How to detect the end of scroll of a webivew - android

I have a custom WebView with the following code:
public class ObservableWebView extends WebView {
private OnScrollChangedCallback mOnScrollChangedCallback;
public ObservableWebView(final Context context) {
super(context);
}
public ObservableWebView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public ObservableWebView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mOnScrollChangedCallback != null) mOnScrollChangedCallback.onScroll(l, t);
}
public OnScrollChangedCallback getOnScrollChangedCallback() {
return mOnScrollChangedCallback;
}
public void setOnScrollChangedCallback(final OnScrollChangedCallback onScrollChangedCallback) {
mOnScrollChangedCallback = onScrollChangedCallback;
}
/**
* Implement in the activity/fragment/view that you want to listen to the webview
*/
public static interface OnScrollChangedCallback {
public void onScroll(int l, int t);
}
}
I use the following method to detect whether scroll has reached the end:
#Override
public void onScroll(int l, int t) {
int tek = (int) Math.floor(webView.getContentHeight() * webView.getScale());
if(tek - webView.getScrollY() == webView.getHeight())
Toast.makeText(getActivity(), "End", Toast.LENGTH_SHORT).show();
}
Problem is it doesn't always work and fails sometimes. Is there are surer way of detecting the end of scroll of a webview that is backward compatible all the way to api level 16?

Related

How to do actions when scroll view reached bottom end?

I have an Activity with a scroll view and 2 buttons, When open this activity both buttons are disabled. What I want is, when I reach the end of the scroll view, enable both buttons to user to accept or decline the content. How can I do this in simple way.
Button before enabled
Thanks in advance.
I have done this things with webView here is my code, hope it will help you.
webView.setOnScrollChangedCallback(new ObservableWebView.OnScrollChangedCallback() {
#Override
public void onScroll(int l, int t) {
int tek = (int) Math.floor(webView.getContentHeight() * webView.getScale());
if (tek - webView.getScrollY() <= webView.getHeight() + 5) {
// enable your button
}
}
});
this is the class
public class ObservableWebView extends WebView
{
private OnScrollChangedCallback mOnScrollChangedCallback;
public ObservableWebView(final Context context)
{
super(context);
}
public ObservableWebView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
}
public ObservableWebView(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
}
#Override
protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt)
{
super.onScrollChanged(l, t, oldl, oldt);
if(mOnScrollChangedCallback != null) mOnScrollChangedCallback.onScroll(l, t);
}
public OnScrollChangedCallback getOnScrollChangedCallback()
{
return mOnScrollChangedCallback;
}
public void setOnScrollChangedCallback(final OnScrollChangedCallback onScrollChangedCallback)
{
mOnScrollChangedCallback = onScrollChangedCallback;
}
/**
* Impliment in the activity/fragment/view that you want to listen to the webview
*/
public static interface OnScrollChangedCallback
{
public void onScroll(int l, int t);
}
}
happy coding.

How can I determine the direction of a vertical ScrollView?

How can I determine the direction of a vertical ScrollView?
I need to hide and display another linear layout accoding to scrollview scroll
You can use the onScrollChanged(int l, int t, int oldl, int oldt) method for that. As there isn't a setter for a listener, but just that method, you will have to create your own ScrollView class and override that method and do your thing in your implementation.
public class ObservableScrollView extends ScrollView {
private static final int DEFAULT_THRESHOLD_DP = 4;
private ScrollDirectionListener scrollDirectionListener;
private int scrollThreshold;
public ObservableScrollView(Context context) {
this(context, null);
}
public ObservableScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ObservableScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
scrollThreshold = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_THRESHOLD_DP, context.getResources().getDisplayMetrics());
}
#Override
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
super.onScrollChanged(x, y, oldX, oldY);
if (Math.abs(y - oldY) > scrollThreshold && scrollDirectionListener != null) {
if (y > oldY) {
scrollDirectionListener.onScrollUp(Math.abs(y - oldY));
} else {
scrollDirectionListener.onScrollDown(Math.abs(y - oldY));
}
}
}
public void setScrollThresholdInPx(int px) {
scrollThreshold = px;
}
public void setScrollThresholdInDp(Context context, float dp) {
scrollThreshold = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}
public void setOnScrollDirectionListener(ScrollDirectionListener listener) {
scrollDirectionListener = listener;
}
public interface ScrollDirectionListener {
void onScrollDown(int pixels);
void onScrollUp(int pixels);
}}
got answer :) use this custom scrollview
ScrollView.setOnScrollDirectionListener(new ObservableScrollView.ScrollDirectionListener() {
#Override
public void onScrollDown(int pixels) {
contenttool.setVisibility(View.INVISIBLE);
}
#Override
public void onScrollUp(int pixels) {
contenttool.setVisibility(View.VISIBLE);
}
});

How to apply a custom view in Xamarin .axml for Android

I've been working on implementing the fading action bar and parallax scrolling into my Android UI in my Xamarin app. I needed to extend my ScrollView, and now it's called a NotifyingScrollView. How do i style my .axml now. I can't just write NotifyingScrollView in my axml,
namespace NightOut.UiComponents
{
class NotifyingScrollView : ScrollView
{
public interface IOnScrollChangedListener
{
void OnScrollChanged(ScrollView who, int l, int t, int oldl, int oldt);
}
private IOnScrollChangedListener mOnScrollChangedListener { get; set; }
public NotifyingScrollView(Context context) : base(context)
{
}
public NotifyingScrollView(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public NotifyingScrollView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
}
[Android.Runtime.Register("onScrollChanged", "(IIII)V", "GetOnScrollChanged_IIIIHandler")]
protected override void OnScrollChanged(int l, int t, int oldl, int oldt)
{
base.OnScrollChanged(l, t, oldl, oldt);
if (mOnScrollChangedListener != null)
{
mOnScrollChangedListener.OnScrollChanged(this, l, t, oldl, oldt);
}
}
}
}
Generic example:
namespace My.Namespace
{
class MyCustomView : View
{
}
}
Is used in following way in .axml
<my.namespace.MyCustomView />
Or in your specific example:
<nightout.uicomponents.NotifyingScrollView />
Do mind case, namespace in .axml is lowercase, classname is same case as C# declaration.

Android Spinner OnItemSelected not called with the same item

First of all, I know that this was asked several time, but on newer android versions it looks like that the suggested solutions doesn't work.
I need that my spinner call OnItemSelected even when the user select the same item twice.
I've found this class that should do the trick:
public class NDSpinner extends Spinner {
private int lastSelected = 0;
private static Method s_pSelectionChangedMethod = null;
static {
try {
Class noparams[] = {};
Class targetClass = AdapterView.class;
s_pSelectionChangedMethod = targetClass.getDeclaredMethod("selectionChanged", noparams);
if (s_pSelectionChangedMethod != null) {
s_pSelectionChangedMethod.setAccessible(true);
}
} catch( Exception e ) {
Log.e("Custom spinner, reflection bug:", e.getMessage());
throw new RuntimeException(e);
}
}
public NDSpinner(Context context) {
super(context);
}
public NDSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NDSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(this.lastSelected == this.getSelectedItemPosition())
testReflectionForSelectionChanged();
if(!changed)
lastSelected = this.getSelectedItemPosition();
super.onLayout(changed, l, t, r, b);
}
public void testReflectionForSelectionChanged() {
try {
Class noparams[] = {};
s_pSelectionChangedMethod.invoke(this, noparams);
} catch (Exception e) {
Log.e("Custom spinner, reflection bug: ", e.getMessage());
e.printStackTrace();
}
}
#Override
public void onClick(DialogInterface dialog, int which) {
super.onClick(dialog, which);
}
}
This infact works, but it has a bug: it call twice the item the first time :(
Can anybody tell me how can I solve this ?
Thanks mates.
I've solved using this class:
public class NDSpinner extends Spinner {
public NDSpinner(Context context)
{ super(context); }
public NDSpinner(Context context, AttributeSet attrs)
{ super(context, attrs); }
public NDSpinner(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
#Override public void
setSelection(int position, boolean animate)
{
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position, animate);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
#Override public void
setSelection(int position)
{
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}
Thanks anyway :)
For me, I extended AppCompatSpinner.
Also if your Spinneris in XML for layout, remember to change your
<Spinner...
to
<com.example.util.NDSpinner...

listening to scroll events horizontalscrollview android

I am trying to listen to the event when the HorizontalScrollView is scrolled. Tried this but it does not print anything.
HorizontalScrollView headerScrollView = new HorizontalScrollView(this);
headerScrollView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
Log.i("hv1",event.toString());
Log.i("hv1","HELLO");
return false;
}
});
The actual problem is, I want to scroll two HorizontalScrollView at a time..ie; both of them need to scroll simultaneously when atleast one of them scrolled.
any workaround?
I used the answer below and then tried implementing this but I am not sure how I need to use the methods in the class.
TestHorizontalScrollView headerScrollView = (TestHorizontalScrollView) findViewById(R.id.headerHv);
Is this the way I need to point to the hsv element in the layout file?
You may want to try creating your own custom class that extends HorizontalScrollView and overriding the onScrollChanged() function as such
public class TestHorizontalScrollView extends HorizontalScrollView {
public TestHorizontalScrollView(Context context) {
super(context);
}
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
// TODO Auto-generated method stub
Log.i("Scrolling", "X from ["+oldl+"] to ["+l+"]");
super.onScrollChanged(l, t, oldl, oldt);
}
}
This overriden function will catch all changes to the scroll position even when the view is not being touched. This should keep your scroll views in sync.
old question, but maybe helpful. You can do something like this:
scrollOne = (HorizontalScrollView)findViewById(R.id.horizontal_one);
scrollTwo = (HorizontalScrollView)findViewById(R.id.horizontal_two);
scrollTwo.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View view, MotionEvent event) {
// TODO Auto-generated method stub
int scrollX = view.getScrollX();
int scrollY = view.getScrollY();
scrollOne.scrollTo(scrollX, scrollY);
return false;
}
});
ScrollView with Listener, api < 23
write below in your code
MyHorizontalScrollView scrollView = (MyHorizontalScrollView)view.findViewById(R.id.scrollViewBrowse);
scrollView.setOnScrollChangedListener(new MyHorizontalScrollView.OnScrollChangedListener() {
#Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {
}
});
MyHorizontalScrollView
public class MyHorizontalScrollView extends ScrollView {
public OnScrollChangedListener mOnScrollChangedListener;
public MyHorizontalScrollView(Context context) {
super(context);
}
public MyHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mOnScrollChangedListener != null) {
mOnScrollChangedListener.onScrollChanged(l, t, oldl, oldt);
}
}
public void setOnScrollChangedListener(OnScrollChangedListener onScrollChangedListener){
this.mOnScrollChangedListener = onScrollChangedListener;
}
public interface OnScrollChangedListener{
void onScrollChanged(int l, int t, int oldl, int oldt);
}
}
* Xml file *
<MyHorizontalScrollView
android:id="#+id/scrollViewBrowse"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:background="#drawable/backgroung"
android:padding="10dp">
</MyHorizontalScrollView>
To Avoid the the Api Level Problem... follow this.
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
int scrollY = scrollView.getScrollY();
int scrollX = scrollView.getScrollX();
if (scrollY > 500) {
} else {
}
}
});
you can try this, i've tried so many ways, but none of them meet my needs, and then i tried to do it myself, and i succeed , and it seems good , it's smooth.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.szl.fundlistdemo.WrapContentListView
android:id="#+id/left_lv"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:scrollbars="none"/>
<HorizontalScrollView
android:id="#+id/hscrollview"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.szl.fundlistdemo.WrapContentListView
android:id="#+id/right_lv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</HorizontalScrollView>
</LinearLayout>
</ScrollView>
public class WrapContentListView extends ListView{
public WrapContentListView(Context context) {
super(context);
}
public WrapContentListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WrapContentListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
Based #Dipak's answer In kotlin:
binding.scrollList.viewTreeObserver.addOnScrollChangedListener {
val X = binding.scrollList.scrollX
val Y = binding.scrollList.scrollY
}

Categories

Resources