Skip to content

Commit a26a03e

Browse files
authored
fix(android): ScrollView BadParcelableException (#10213)
1 parent 0183f7e commit a26a03e

File tree

6 files changed

+91
-75
lines changed

6 files changed

+91
-75
lines changed
Binary file not shown.

packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/GridLayout.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,9 @@ private void addToMap(View child) {
223223
}
224224

225225
private void removeFromMap(View child) {
226-
this.map.get(child).child = null;
227-
this.map.remove(child);
226+
if (this.map.containsKey(child)) {
227+
this.map.remove(child).child = null;
228+
}
228229
}
229230

230231
@Override

packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/HorizontalScrollView.java

Lines changed: 6 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22

33
import android.content.Context;
44
import android.graphics.Rect;
5-
import android.os.Parcel;
65
import android.os.Parcelable;
76
import android.util.AttributeSet;
87
import android.view.MotionEvent;
98
import android.view.View;
109
import android.view.ViewGroup;
11-
import android.view.ViewParent;
1210
import android.widget.FrameLayout;
1311

14-
import androidx.annotation.NonNull;
15-
1612
/**
1713
* @author hhristov
1814
*/
@@ -23,7 +19,7 @@ public class HorizontalScrollView extends android.widget.HorizontalScrollView {
2319
private int contentMeasuredWidth = 0;
2420
private int contentMeasuredHeight = 0;
2521
private int scrollableLength = 0;
26-
private SavedState mSavedState;
22+
private ScrollSavedState mSavedState;
2723
private boolean isFirstLayout = true;
2824
private boolean scrollEnabled = true;
2925

@@ -180,7 +176,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
180176

181177
this.mIsLayoutDirty = false;
182178
// Give a child focus if it needs it
183-
if (this.mChildToScrollTo != null && isViewDescendantOf(this.mChildToScrollTo, this)) {
179+
if (this.mChildToScrollTo != null && Utils.isViewDescendantOf(this.mChildToScrollTo, this)) {
184180
this.scrollToChild(this.mChildToScrollTo);
185181
}
186182

@@ -194,7 +190,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
194190

195191
final int scrollRange = Math.max(0, childWidth - (right - left - this.getPaddingLeft() - this.getPaddingRight()));
196192
if (this.mSavedState != null) {
197-
scrollX = (this.isLayoutRtl() == mSavedState.isLayoutRtl) ? mSavedState.scrollPosition : (scrollRange - this.mSavedState.scrollPosition);
193+
scrollX = this.isLayoutRtl() ? scrollRange - mSavedState.scrollOffsetFromStart : mSavedState.scrollOffsetFromStart;
198194
mSavedState = null;
199195
} else {
200196
if (this.isLayoutRtl()) {
@@ -228,7 +224,7 @@ protected void onDetachedFromWindow() {
228224

229225
@Override
230226
protected void onRestoreInstanceState(Parcelable state) {
231-
SavedState ss = (SavedState) state;
227+
ScrollSavedState ss = (ScrollSavedState) state;
232228
super.onRestoreInstanceState(ss.getSuperState());
233229
this.mSavedState = ss;
234230
this.requestLayout();
@@ -237,9 +233,8 @@ protected void onRestoreInstanceState(Parcelable state) {
237233
@Override
238234
protected Parcelable onSaveInstanceState() {
239235
Parcelable superState = super.onSaveInstanceState();
240-
SavedState ss = new SavedState(superState);
241-
ss.scrollPosition = this.getScrollX();
242-
ss.isLayoutRtl = this.isLayoutRtl();
236+
ScrollSavedState ss = new ScrollSavedState(superState);
237+
ss.scrollOffsetFromStart = isLayoutRtl() ? -this.getScrollX() : this.getScrollX();
243238
return ss;
244239
}
245240

@@ -258,58 +253,4 @@ private void scrollToChild(View child) {
258253
private boolean isLayoutRtl() {
259254
return (this.getLayoutDirection() == LAYOUT_DIRECTION_RTL);
260255
}
261-
262-
/**
263-
* Return true if child is a descendant of parent, (or equal to the parent).
264-
*/
265-
static boolean isViewDescendantOf(View child, View parent) {
266-
if (child == parent) {
267-
return true;
268-
}
269-
270-
final ViewParent theParent = child.getParent();
271-
return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
272-
}
273-
274-
static class SavedState extends BaseSavedState {
275-
public int scrollPosition;
276-
public boolean isLayoutRtl;
277-
278-
SavedState(Parcelable superState) {
279-
super(superState);
280-
}
281-
282-
public SavedState(Parcel source) {
283-
super(source);
284-
scrollPosition = source.readInt();
285-
isLayoutRtl = source.readInt() == 0;
286-
}
287-
288-
@Override
289-
public void writeToParcel(Parcel dest, int flags) {
290-
super.writeToParcel(dest, flags);
291-
dest.writeInt(scrollPosition);
292-
dest.writeInt(isLayoutRtl ? 1 : 0);
293-
}
294-
295-
@NonNull
296-
@Override
297-
public String toString() {
298-
return "HorizontalScrollView.SavedState{"
299-
+ Integer.toHexString(System.identityHashCode(this))
300-
+ " scrollPosition=" + scrollPosition
301-
+ " isLayoutRtl=" + isLayoutRtl + "}";
302-
}
303-
304-
public static final Creator<SavedState> CREATOR
305-
= new Creator<SavedState>() {
306-
public SavedState createFromParcel(Parcel in) {
307-
return new SavedState(in);
308-
}
309-
310-
public SavedState[] newArray(int size) {
311-
return new SavedState[size];
312-
}
313-
};
314-
}
315256
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.nativescript.widgets;
2+
3+
import android.os.Build;
4+
import android.os.Parcel;
5+
import android.os.Parcelable;
6+
import android.view.View.BaseSavedState;
7+
8+
import androidx.annotation.NonNull;
9+
import androidx.annotation.RequiresApi;
10+
11+
/**
12+
* @author CatchABus
13+
*/
14+
class ScrollSavedState extends BaseSavedState {
15+
public int scrollOffsetFromStart;
16+
17+
ScrollSavedState(Parcelable superState) {
18+
super(superState);
19+
}
20+
21+
public ScrollSavedState(Parcel source) {
22+
super(source);
23+
scrollOffsetFromStart = source.readInt();
24+
}
25+
26+
@RequiresApi(Build.VERSION_CODES.N)
27+
public ScrollSavedState(Parcel source, ClassLoader loader) {
28+
super(source, loader);
29+
scrollOffsetFromStart = source.readInt();
30+
}
31+
32+
@Override
33+
public void writeToParcel(Parcel dest, int flags) {
34+
super.writeToParcel(dest, flags);
35+
dest.writeInt(scrollOffsetFromStart);
36+
}
37+
38+
@NonNull
39+
@Override
40+
public String toString() {
41+
return "ScrollSavedState{"
42+
+ Integer.toHexString(System.identityHashCode(this))
43+
+ " scrollPosition=" + scrollOffsetFromStart
44+
+ "}";
45+
}
46+
47+
public static final Creator<ScrollSavedState> CREATOR = new ClassLoaderCreator<ScrollSavedState>() {
48+
public ScrollSavedState createFromParcel(Parcel in, ClassLoader loader)
49+
{
50+
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? new ScrollSavedState(in, loader) : new ScrollSavedState(in);
51+
}
52+
53+
@Override
54+
public ScrollSavedState createFromParcel(Parcel in)
55+
{
56+
return createFromParcel(in, null);
57+
}
58+
59+
public ScrollSavedState[] newArray(int size) {
60+
return new ScrollSavedState[size];
61+
}
62+
};
63+
}

packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/Utils.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import android.util.Pair;
2222
import android.view.View;
2323
import android.view.ViewGroup;
24+
import android.view.ViewParent;
2425

2526
import androidx.appcompat.content.res.AppCompatResources;
2627
import androidx.core.view.ViewCompat;
@@ -512,6 +513,18 @@ public void run() {
512513
});
513514
}
514515

516+
/**
517+
* Return true if child is a descendant of parent, (or equal to the parent).
518+
*/
519+
static boolean isViewDescendantOf(View child, View parent) {
520+
if (child == parent) {
521+
return true;
522+
}
523+
524+
final ViewParent childParent = child.getParent();
525+
return (childParent instanceof ViewGroup) && isViewDescendantOf((View) childParent, parent);
526+
}
527+
515528
// public static void clearBoxShadow(View view) {
516529
// if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
517530
// return;

packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/VerticalScrollView.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
import android.widget.FrameLayout;
1111
import androidx.core.widget.NestedScrollView;
1212

13-
import org.nativescript.widgets.HorizontalScrollView.SavedState;
14-
1513
/**
1614
* @author hhristov
1715
*/
@@ -22,7 +20,7 @@ public class VerticalScrollView extends NestedScrollView {
2220
private int contentMeasuredWidth = 0;
2321
private int contentMeasuredHeight = 0;
2422
private int scrollableLength = 0;
25-
private SavedState mSavedState;
23+
private ScrollSavedState mSavedState;
2624
private boolean isFirstLayout = true;
2725
private boolean scrollEnabled = true;
2826

@@ -186,7 +184,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
186184

187185
this.mIsLayoutDirty = false;
188186
// Give a child focus if it needs it
189-
if (this.mChildToScrollTo != null && HorizontalScrollView.isViewDescendantOf(this.mChildToScrollTo, this)) {
187+
if (this.mChildToScrollTo != null && Utils.isViewDescendantOf(this.mChildToScrollTo, this)) {
190188
this.scrollToChild(this.mChildToScrollTo);
191189
}
192190

@@ -200,7 +198,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
200198
final int scrollRange = Math.max(0,
201199
childHeight - (bottom - top - this.getPaddingTop() - this.getPaddingBottom()));
202200
if (this.mSavedState != null) {
203-
scrollY = mSavedState.scrollPosition;
201+
scrollY = mSavedState.scrollOffsetFromStart;
204202
mSavedState = null;
205203
}
206204

@@ -232,7 +230,7 @@ public void onDetachedFromWindow() {
232230

233231
@Override
234232
protected void onRestoreInstanceState(Parcelable state) {
235-
SavedState ss = (SavedState) state;
233+
ScrollSavedState ss = (ScrollSavedState) state;
236234
super.onRestoreInstanceState(ss.getSuperState());
237235
this.mSavedState = ss;
238236
this.requestLayout();
@@ -241,8 +239,8 @@ protected void onRestoreInstanceState(Parcelable state) {
241239
@Override
242240
protected Parcelable onSaveInstanceState() {
243241
Parcelable superState = super.onSaveInstanceState();
244-
SavedState ss = new SavedState(superState);
245-
ss.scrollPosition = this.getScrollY();
242+
ScrollSavedState ss = new ScrollSavedState(superState);
243+
ss.scrollOffsetFromStart = this.getScrollY();
246244
return ss;
247245
}
248246

0 commit comments

Comments
 (0)