Can't launch ShowcaseView from fragment in android
I am using the latest ShowcaseView from here
When I tried to use it with demo app and activity, it works, but when I tried to use it with fragments, it crashed my app without logcat errors.
@override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ImageButton saveButton = (ImageButton) view.findViewById(R.id.button_Save);
ViewTarget viewTarget = new ViewTarget(saveButton);
showcaseView = new ShowcaseView.Builder(getActivity())
.setTarget(viewTarget)
.setContentTitle("Reset Button")
.setContentText("This will erase all the data in the table except the line that in progress")
.build();
}
what could be the problem here?
EDIT1:
when i tried to do the same in my fragmentation ability and didn't work, but when i did the same but did the kind that was declared in the fragmentation function and not in the fragment that worked.
EDIT2: I was able to get the error from the logcat.
FATAL EXCEPTION: main
java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:724)
at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
at android.graphics.Bitmap.createBitmap(Bitmap.java:670)
at com.github.amlcurran.showcaseview.ShowcaseView.updateBitmap(ShowcaseView.java:169)
at com.github.amlcurran.showcaseview.ShowcaseView.onGlobalLayout(ShowcaseView.java:343)
at android.view.ViewTreeObserver.dispatchOnGlobalLayout(ViewTreeObserver.java:839)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2050)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1249)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6364)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791)
at android.view.Choreographer.doCallbacks(Choreographer.java:591)
at android.view.Choreographer.doFrame(Choreographer.java:561)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)
I understand the error, but what is the reason for this?
source to share
In my opinion, the best solution is to put the code in the "post" callback of the view so it will be executed when everything is shown.
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.post(new Runnable() {
@Override
public void run() {
// your showcase initialisation code here
showcase();
}
});
}
I tested it and it worked like a charm.
source to share
This appears to be a sync issue. If the call takes place before the presentation is actually displayed on the screen, it does not mean that the width and height must be> 0. It is clear from the source code ShowcaseView
, in updateBitmap()
where it does not work:
bitmapBuffer = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
where getMeasuredWidth()
and getMeasuredHeight()
will be zero before actually drawing.
The work around for this problem is to trigger this with good latency. I am currently using it with a 5s delay and call it onResume()
, withHandler
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
new ShowcaseView.Builder(mActivity)
.setTarget(new ViewTarget(saveMatchButton))
.setContentTitle("This is a demo")
.build();
}
}, 5000);
source to share
I think the best solution is to change the ShowcaseView class (Function updateBitmap ()). Passing any nonzero size values to createBitmap () when getMeasure * returns 0 will produce a valid sized bitmap. Since updateBitmap () will be called again as soon as the view is at its actual size, this is not a problem.
private void updateBitmap()
{
if (bitmapBuffer == null || haveBoundsChanged())
{
if(bitmapBuffer != null)
bitmapBuffer.recycle();
bitmapBuffer = Bitmap.createBitmap(getMeasuredWidth() > 0 ? getMeasuredWidth() : 1,
getMeasuredHeight() > 0 ? getMeasuredHeight() : 1,
Bitmap.Config.ARGB_8888);
}
}
source to share
Even you can write it in RESUME () and make sure that if you write in a resume, you need to keep a flag to be used to avoid the problem of creating more than one showcase above when OnResume () is called.
if (!mShowCaseVisible){
ActionViewTarget target = new ActionViewTarget(getActivity(), ActionViewTarget.Type.HOME);
showcaseView = new ShowcaseView.Builder(getActivity(), true)
.setTarget(target)
.setContentTitle("Home Screen")
.setOnClickListener(this)
.setContentText("Click on top left corner to seemenu.")
.doNotBlockTouches()`enter code here`
.hideOnTouchOutside()
.singleShot(42)
.build();
showcaseView.setButtonText("Next");
mShowCaseVisible = true;
}
source to share