问题
I use the last version of 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 with no 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 thing in my fragmentactivity and didn't work, but when I did the same thing but took a view that declared in the fragmentactivity and not in the fragment it worked.
EDIT2: I managed 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 cause for it?
回答1:
In my opinion the best solution is to place the code within the "post" callback of the view, this way it will be executed when everything is rendered.
@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 worked like a charm.
回答2:
This appears to be a timing issue. If the call happens before the views are actually drawn on screen, it fails saying the width and height should be > 0. This is clear from the source code of ShowcaseView
, in updateBitmap()
function, where it fails:
bitmapBuffer = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
where getMeasuredWidth()
and getMeasuredHeight()
will be zero before actually drawing.
The work around to this issue is to call this with a good delay. I currently use it with a 5s delay and call it from onResume()
, with the help of a Handler
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
new ShowcaseView.Builder(mActivity)
.setTarget(new ViewTarget(saveMatchButton))
.setContentTitle("This is a demo")
.build();
}
}, 5000);
回答3:
I think a better solution is to change the ShowcaseView class (Function updateBitmap()). Passing any non-zero dimension values to the createBitmap() function when getMeasure* returns 0 would ensure the bitmap is created with a valid size. Since updateBitmap() function will be called again as soon as the view gets is actual size, this poses no 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);
}
}
回答4:
According to this answer, the ShowcaseView
should be built in onCreateView()
.
回答5:
Even you can write it down in RESUME() and make sure if you are writing in resume then you must have to maintain a flag which will be used to avoid issue of building more then one showcase one above on whenever OnResume() will be 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;
}
来源:https://stackoverflow.com/questions/23570284/cant-run-showcaseview-from-fragment-in-android