Synchronizing two Horizontal Scroll Views in Android
Asked Answered
C

2

5

I tried following the advice from this post Synchronise ScrollView scroll positions - android but running into a problem.

Background - I want a table layout with both horizontal and vertical scrolling, but I want the first row and first column always present - like freeze pane with excel. Unfortunately it seems that is close to impossible with Android java programming...causing me such a headache. I have it set up so that if I can just synchronize these two horizontalscrollviews then I will have the table working the way I want.

I followed the advice from the posted link above and the problem I have is this. The app force closes when I implement the

scrollView1.setScrollViewListener(this);

I think the problem may be the way I am declaring the ObservableScrollViews. I am not using XML - all objects are created programatically. I tried using

private ObservableScrollView oScrollViewOne = new ObservableScrollView (this);

but this is causing a force close as well. (Can I just create a regular scrollview, assign it an ID and then use

scrollView1 = (ObservableScrollView) findViewById(ID); where ID is the integer number I gave the scrollview.

I'm wondering what to make of the comments below and how to use them if I am not using the XML layout.

And we should specify this new ObservableScrollView class in the layout, instead of the existing ScrollView tags.

com.test.ObservableScrollView android:id="@+id/scrollview1" ...

Any other suggestions to implement synchronizing two horizontalscroll views, with the explicit code - not just a suggestion to use OnTouchMotionEvent or other idea without giving the code, as I've seen before.

Here's the error code

10-23 23:33:08.631: ERROR/AndroidRuntime(18187): FATAL EXCEPTION: main
10-23 23:33:08.631: ERROR/AndroidRuntime(18187): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.glen.apps.TeacherAidePro/com.glen.apps.TeacherAidePro.TeacherAidePro}: java.lang.NullPointerException
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2709)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2803)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.app.ActivityThread.access$2300(ActivityThread.java:135)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2136)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.os.Looper.loop(Looper.java:144)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.app.ActivityThread.main(ActivityThread.java:4937)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at java.lang.reflect.Method.invokeNative(Native Method)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at java.lang.reflect.Method.invoke(Method.java:521)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at dalvik.system.NativeStart.main(Native Method)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187): Caused by: java.lang.NullPointerException
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.content.ContextWrapper.getResources(ContextWrapper.java:80)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.view.View.<init>(View.java:1810)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.view.View.<init>(View.java:1856)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.view.ViewGroup.<init>(ViewGroup.java:299)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.widget.FrameLayout.<init>(FrameLayout.java:83)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.widget.ScrollView.<init>(ScrollView.java:137)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.widget.ScrollView.<init>(ScrollView.java:133)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.widget.ScrollView.<init>(ScrollView.java:129)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at com.glen.apps.TeacherAidePro.ObservableScrollView.<init>(ObservableScrollView.java:12)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at com.glen.apps.TeacherAidePro.TeacherAidePro.<init>(TeacherAidePro.java:119)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at java.lang.Class.newInstanceImpl(Native Method)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at java.lang.Class.newInstance(Class.java:1429)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.app.Instrumentation.newActivity(Instrumentation.java:1036)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2701)
10-23 23:33:08.631: ERROR/AndroidRuntime(18187):     ... 11 more

Here's line 12

 1. package com.glen.apps.TeacherAidePro;
 2.
 3. import android.content.Context;
 4. import android.util.AttributeSet;
 5. import android.widget.ScrollView;
 6.
 7. public class ObservableScrollView extends ScrollView {
 8.
 9.   private IScrollListener listener = null;    
10.
11.   public ObservableScrollView(Context context) {
12.       super(context);
  }
Crawley answered 24/10, 2011 at 1:25 Comment(2)
Could you post the exceptions you get from logcat? It will help pinpoint the problem.Cummine
Posted in original post. thanks.Crawley
C
6

The error points to a null pointer in a constructor in your ObservableScrollView. Could you please post the constructor, as well as line 12 on its own?

One possible issue I am seeing with the way your XML and custom scroll view interact is that your custom scroll view is an inner class. See this page for how to declare an inner class custom component in XML, or move it to an external class. I usually put it in an external class, but if you wanted to keep it as an inner class it would be something like

<view
    class="com.glen.apps.TeacherAidePro$ObservableScrollView"
.../>

I don't think this explains your null pointer exception though, so please post your ObservableScrollView class.

EDIT:

If you insist on doing everything in Java, here is a working example:

private ObservableScrollView scrollView1 = null;
private ObservableScrollView scrollView2 = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LinearLayout parent = new LinearLayout(this);
    parent.setOrientation(LinearLayout.HORIZONTAL);
    parent.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
            LayoutParams.FILL_PARENT));
    parent.setWeightSum(2.0f);

    scrollView1 = new ObservableScrollView(this);
    scrollView1.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
            LayoutParams.FILL_PARENT, 1.0f));
    scrollView2 = new ObservableScrollView(this);
    scrollView2.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
            LayoutParams.FILL_PARENT, 1.0f));

    scrollView1.setScrollViewListener(new ScrollViewListener() {
        public void onScrollChanged(ObservableScrollView scrollView, int x,
                int y, int oldx, int oldy) {
            scrollView2.scrollTo(x, y);
        }
    });
    scrollView2.setScrollViewListener(new ScrollViewListener() {
        public void onScrollChanged(ObservableScrollView scrollView, int x,
                int y, int oldx, int oldy) {
            scrollView1.scrollTo(x, y);
        }
    });

    TextView tv1 = new TextView(this);
    tv1.setText("TEXT1TEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXT");
    tv1.setTextSize(36.0f);
    scrollView1.addView(tv1);

    TextView tv2 = new TextView(this);
    tv2.setText("TEXT2TEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXTTEXT");
    tv2.setTextSize(36.0f);
    scrollView2.addView(tv2);

    parent.addView(scrollView1);
    parent.addView(scrollView2);
    parent.invalidate();

    setContentView(parent);
}

Basically, this creates two scroll views side by side, with weights of 1.0 each, and puts them in a LinearLayout with total weight on the layout of 2.0, so they each get half the width.

However, I highly recommend getting used to XML as it is much, much easier (in my opinion) to create layouts. It is also easier to spot mistakes, and the nested form of XML makes it easier to read. Anyway, hope this clears things up.

Cummine answered 24/10, 2011 at 12:24 Comment(8)
Thanks. I'll post it this afternoon. One point is that I don't use xml at all - I"m declaring everything in the actual main activity code. However, the original post on how to sync two horizontal scrolls dealt with using and xml layout which I am trying to avoid (and also there was not enough explanation of the xml code)Crawley
I have provided a working example of how to do it in Java. I recommend getting used to XML though, because once you get used to it it is pretty straightforward!Cummine
The reason I don't use XML is that the app dynamically adds rows/columns to the layout when the use clicks on various buttons. As far as I've seen, this is much easier to do using java codeCrawley
If your ObservableScrollView is the same as the one in the example you linked to, then I don't think it is the problem. Please post the onCreate method in the activity where you declare and initialize your view. Also see my example for how I achieved synchronized scroll views.Cummine
Thank you so much for all your help so far. I am going to create a new app with just the basic two scrollviews using java that you posted above and see if I can get that to work. If so then that may help me diagnose my problem betterCrawley
YES!!!! Thanks so much for your help. Got the synchronized scrollviews working. I set my ObservableScrollView to extend HorizontalScrollView instead of ScrollView. I also had not declared the ObservableScrollViews as null...that seemed to stop the force close. It's working great. Thanks so much for your help Craigy.Crawley
-Craigy I am also using the code but it is throwing me null pointer expection can you help me – hemantTanto
any idea about this one ? #58848891Barrada
N
1

This is my solution further explanation in the code:

//This should be inside yout oncreate
syncScrolls(firstView, secondView;
        syncScrolls(secondView, firstView);




    //This method accept 2 horizontal scroll views, but you could improve it passing an array. 
        private void syncScrolls(final HorizontalScrollView currentView, final HorizontalScrollView otherView) {

//This create the Gesture Listener where we override the methods we need
                GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() {
                    @Override
                    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//Here onfling just return true, this way doesnt happens
                        return true;
                    }
                    @Override
                    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//On scroll we sync the movement of the both views
                        otherView.scrollTo(currentView.getScrollX(), 0);
                        return super.onScroll(e1, e2, distanceX, distanceY);
                    }
                    @Override
                    public boolean onDown(MotionEvent e) {
                        return true;
                    }
                };
        //This create the gesture detectors that implements the previous custom gesture listener
                final GestureDetector gestureDetector = new GestureDetector(this, gestureListener);
        //And finally we set everything to the views we need
                currentView.setOnTouchListener(new View.OnTouchListener() {
                    public boolean onTouch(View v, MotionEvent event) {
                        return gestureDetector.onTouchEvent(event);
                    }
                });

        }

Im not sure this is a completely good answers, well as I mentioned before you can improve this by using an array, insted of calling the method for each view to sync, int his case just 2. Also onFling is prevented instead of being sync, if your scroll view is too long, this could not be user friendly. And finally, there is still a litle problem if the user does a tiny fling, but its a very rare case.

Navigable answered 13/11, 2015 at 18:33 Comment(1)
I decided to try and sync the scrollviews inside of OnTouch - just move the otherView.scrollTo(currentView.getScrollX(), 0) and it worked great. I don't need the onScroll method at all.El

© 2022 - 2024 — McMap. All rights reserved.