Reputation: 119
So, I have a viewflipper which is filled with several webviews. I've then extended the WebView class in order to catch the motions for the viewflipper.
The problem is that when I swipe, the app crashes and gives me the following error:
10-09 17:23:14.443: E/MessageQueue-JNI(21126): java.lang.NullPointerException: Attempt to invoke virtual method 'int android.widget.ViewFlipper.getDisplayedChild()' on a null object reference
10-09 17:23:14.443: E/MessageQueue-JNI(21126): at com.test.hamnarbetare.CustomWebView.onTouchEvent(CustomWebView.java:55)
The code can be viewed here:
package com.test.hamnarbetare;
import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.webkit.WebView;
import android.widget.ViewFlipper;
public class CustomWebView extends WebView {
private float lastX;
private ViewFlipper viewFlipper;
float downXValue;
long downTime;
private float lastTouchX, lastTouchY;
private boolean hasMoved = false;
public CustomWebView(Context context) {
super(context);
viewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);
}
public boolean onTouchEvent(MotionEvent evt) {
boolean consumed = super.onTouchEvent(evt);
if (isClickable()) {
switch (evt.getAction()) {
case MotionEvent.ACTION_DOWN:
lastTouchX = evt.getX();
lastTouchY = evt.getY();
downXValue = evt.getX();
downTime = evt.getEventTime();
hasMoved = false;
break;
case MotionEvent.ACTION_MOVE:
hasMoved = moved(evt);
break;
case MotionEvent.ACTION_UP:
float currentX = evt.getX();
long currentTime = evt.getEventTime();
float difference = Math.abs(downXValue - currentX);
long time = currentTime - downTime;
if ( (downXValue < currentX) && (time < 220) && (difference > 100) ) {
if (viewFlipper.getDisplayedChild() == 1)
break;
viewFlipper.setInAnimation(getContext(), R.anim.slide_in_from_right); // Next screen comes in from right.
viewFlipper.setOutAnimation(getContext(), R.anim.slide_out_to_left); // Current screen goes out from left.
// Display previous screen.
viewFlipper.showPrevious();
}
if ( (downXValue > currentX) && (time < 220) && (difference > 100) ) {
if (viewFlipper.getDisplayedChild() == 0)
break;
viewFlipper.setInAnimation(getContext(), R.anim.slide_in_from_left); // Next screen comes in from left.
viewFlipper.setOutAnimation(getContext(), R.anim.slide_out_to_right); // Current screen goes out from right.
// Display next screen.
viewFlipper.showNext();
}
//if (!moved(evt)) performClick();
break;
}
}
return consumed || isClickable();
}
private boolean moved(MotionEvent evt) {
return hasMoved || Math.abs(evt.getX() - lastTouchX) > 10.0 || Math.abs(evt.getY() - lastTouchY) > 10.0;
}
/*public boolean onTouchEvent(MotionEvent touchevent) {
switch (touchevent.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = touchevent.getX();
break;
case MotionEvent.ACTION_UP:
float currentX = touchevent.getX();
// Handling left to right screen swap.
if (lastX < currentX) {
// If there aren't any other children, just break.
if (viewFlipper.getDisplayedChild() == 0)
break;
viewFlipper.setInAnimation(getContext(), R.anim.slide_in_from_left); // Next screen comes in from left.
viewFlipper.setOutAnimation(getContext(), R.anim.slide_out_to_right); // Current screen goes out from right.
// Display next screen.
viewFlipper.showNext();
}
// Handling right to left screen swap.
if (lastX > currentX) {
// If there is a child (to the left), just break.
if (viewFlipper.getDisplayedChild() == 1)
break;
viewFlipper.setInAnimation(getContext(), R.anim.slide_in_from_right); // Next screen comes in from right.
viewFlipper.setOutAnimation(getContext(), R.anim.slide_out_to_left); // Current screen goes out from left.
// Display previous screen.
viewFlipper.showPrevious();
}
break;
}
return false;
}*/
}
For some reason, viewFlipper is unknown at this point. HOWEVER if I replace the onTouchEvent with the previous onTouchEvent which is located at the bottom, it all works fine and I can't understand why! Any ideas?
EDIT: Layout xml file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingTop="10dp" >
<ViewFlipper
android:id="@+id/viewFlipper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.70" />
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/actionbar_bg" >
<Button
android:id="@+id/btn_left"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_weight="0.23"
android:text="@string/previous" />
<TextView
android:id="@+id/page_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.23"
android:gravity="center"
android:text=""
android:textColor="#FFFFFF" />
<Button
android:id="@+id/btn_right"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_weight="0.35"
android:text="@string/next" />
</LinearLayout>
</LinearLayout>
Upvotes: 1
Views: 865
Reputation: 213
The problem is that CustomWebView can't find R.id.viewFlipper with findViewById.
What you need to do is lookup R.id.viewFlipper in the ParentActivity and pass the ViewFlipper in the CustomWebView constructor.
Example code below, not compiled/tested.
CustomWebView.java
public CustomWebView(Context context, ViewFlipper viewFlipper) {
super(context);
this.viewFlipper = viewFlipper;
}
ParentActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout_xml);
ViewFlipper viewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);
CustomWebView webView = new CustomWebView(this, viewFlipper);
// TODO: Add webView to viewFlipper
}
Upvotes: 1