I solved the problem through adding a child view to ShowCaseView
.
UPD,
I've been asked to share the solution, so I'll share with all code that I use.
Here's my complete code as to using ShowCaseView
:
I use a Fragment
to show it, therefore I don't need to copy code in every time, also I made some improvements to make life easier using it:
frShowCase.java:
/**
* Created by Movsar Bekaev on 02/09/2015.
*/
public class frShowCase extends Fragment {
static boolean is_sc_done;
static ArrayList<xSchowCaseTarget> elements;
static ShowcaseView sv;
int svStep = 0;
RelativeLayout.LayoutParams svButtonParams;
TextView tvSvTitle, tvSvDetail;
View additional_view = null;
Handler mHandler;
//SHOWCASE THING************************************
private View.OnClickListener showCaseListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
sv.hideButton();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
showCaseSwitcher();
sv.showButton();
}
}, 50);
}
};
public static frShowCase newInstance(ArrayList<xSchowCaseTarget> _elements) {
frShowCase f = new frShowCase();
Bundle args = new Bundle();
elements = new ArrayList<xSchowCaseTarget>();
sv = null;
for (xSchowCaseTarget se : _elements) {
elements.add(se);
}
is_sc_done = false;
f.setArguments(args);
return f;
}
public void svSetButtonPosition(cbActivity.position buttonPortraitPosition) {
switch (buttonPortraitPosition) {
case BOTTOM_LEFT:
svButtonParams = new RelativeLayout.LayoutParams((int) getActivity().getResources().getDimension(R.dimen.btns_width), (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
svButtonParams.topMargin = 0;
break;
case BOTTOM_RIGHT:
svButtonParams = new RelativeLayout.LayoutParams((int) getActivity().getResources().getDimension(R.dimen.btns_width), (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
svButtonParams.topMargin = 0;
break;
case TOP_LEFT:
svButtonParams = new RelativeLayout.LayoutParams((int) getActivity().getResources().getDimension(R.dimen.btns_width), (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
svButtonParams.topMargin = (int) getActivity().getResources().getDimension(R.dimen.btns_heigh);
break;
case TOP_RIGHT:
svButtonParams = new RelativeLayout.LayoutParams((int) getActivity().getResources().getDimension(R.dimen.btns_width), (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
svButtonParams.topMargin = (int) getActivity().getResources().getDimension(R.dimen.btns_heigh);
break;
case CENTER:
svButtonParams = new RelativeLayout.LayoutParams((int) getActivity().getResources().getDimension(R.dimen.btns_width), (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.CENTER_IN_PARENT);
svButtonParams.topMargin = 0;
break;
case FILL_BOTTOM:
svButtonParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
svButtonParams.topMargin = 0;
break;
case FILL_TOP:
svButtonParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
svButtonParams.topMargin = (int) getActivity().getResources().getDimension(R.dimen.btns_heigh);
break;
case BOTTOM_CENTER:
svButtonParams = new RelativeLayout.LayoutParams((int) getActivity().getResources().getDimension(R.dimen.btns_width), (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
svButtonParams.topMargin = 0;
break;
case CENTER_TOP:
svButtonParams = new RelativeLayout.LayoutParams((int) getActivity().getResources().getDimension(R.dimen.btns_width), (int) getActivity().getResources().getDimension(R.dimen.btns_heigh));
svButtonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
svButtonParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
svButtonParams.topMargin = (int) getActivity().getResources().getDimension(R.dimen.btns_heigh);
break;
}
sv.setButtonPosition(svButtonParams);
}
private void svSetUpOtherView() {
sv.setContentTitle("");
sv.setContentText("");
additional_view = View.inflate(getActivity(), R.layout.showcase_text, null);
RelativeLayout.LayoutParams lps = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lps.addRule(RelativeLayout.CENTER_IN_PARENT);
tvSvTitle = (TextView) additional_view.findViewById(R.id.tvSvTitle);
tvSvTitle.setText(elements.get(svStep).title);
tvSvDetail = (TextView) additional_view.findViewById(R.id.tvSvDetailText);
tvSvDetail.setText(elements.get(svStep).description);
sv.addView(additional_view, 0, lps);
}
private void showCaseSwitcher() {
if (svStep < elements.size()) {
if (additional_view != null)
sv.removeView(additional_view);
sv.setShowcase(elements.get(svStep).target, true);
svSetButtonPosition(elements.get(svStep).b_pos);
if (elements.get(svStep).use_splashscreen) {
svSetUpOtherView();
} else {
sv.setContentTitle(elements.get(svStep).title);
sv.setContentText(elements.get(svStep).description);
}
svStep++;
} else {
ViewGroup mRootView = (ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content);
for (View v : getAllChildrenBFS(mRootView)) v.setEnabled(true);
sv.hide();
if (elements.get(svStep - 1).title.equals(getString(R.string.sv_intention_addweek_title))) {
final Message m1 = mHandler.obtainMessage(123);
mHandler.sendMessage(m1);
}
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
}
}
public void setHandler(Handler handler) {
this.mHandler = handler;
}
@Override
public void onAttach(Activity ac) {
super.onAttach(ac);
Log.d("123", "onattach");
}
private List<View> getAllChildrenBFS(View v) {
List<View> visited = new ArrayList<View>();
List<View> unvisited = new ArrayList<View>();
unvisited.add(v);
while (!unvisited.isEmpty()) {
View child = unvisited.remove(0);
visited.add(child);
if (!(child instanceof ViewGroup)) continue;
ViewGroup group = (ViewGroup) child;
final int childCount = group.getChildCount();
for (int i=0; i<childCount; i++) unvisited.add(group.getChildAt(i));
}
return visited;
}
@Override
public void onCreate(Bundle b) {
super.onCreate(b);
Log.d("123", "oncreate");
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//SHOWCASE INITIALIZATION THING*************************************************************
if (!is_sc_done && frShowCase.elements != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = pm.isScreenOn();
if (isScreenOn) {
is_sc_done = true;
ViewGroup mRootView = (ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content);
for (View v : getAllChildrenBFS(mRootView)) v.setEnabled(false);
cbActivity.BoolToPref(getActivity().getLocalClassName(), false);
sv = new ShowcaseView.Builder(getActivity())
.setTarget(frShowCase.elements.get(0).target)
.setContentTitle(frShowCase.elements.get(svStep).title)
.setContentText(frShowCase.elements.get(svStep).description)
.setStyle(R.style.CustomShowcaseTheme)
.setOnClickListener(showCaseListener)
.build();
if (elements.get(svStep).use_splashscreen)
svSetUpOtherView();
svSetButtonPosition(frShowCase.elements.get(0).b_pos);
sv.setButtonText(getActivity().getString(R.string.next));
svStep++;
}
}
return sv;
}
//**************************************************************************************
return container;
}
}
Here is a class for targets I use to pass Targets
from Activities
to that Fragment
xShowCaseTargets.java
import com.github.amlcurran.showcaseview.targets.Target;
/**
* Created by Movsar Bekaev on 15/09/2015.
*/
public class xSchowCaseTarget{
protected cbActivity.position b_pos = cbActivity.position.BOTTOM_RIGHT;
protected Target target = null;
protected String title = "";
protected String description = "";
protected boolean use_splashscreen = false;
public xSchowCaseTarget(Target target, String title, String desc, cbActivity.position position, Boolean useSplash) {
this.b_pos = position;
this.target = target;
this.title = title;
this.description = desc;
this.use_splashscreen = useSplash;
}
public xSchowCaseTarget(Target target, String title, String desc, cbActivity.position position) {
this.b_pos = position;
this.target = target;
this.title = title;
this.description = desc;
this.use_splashscreen = false;
}
}
This is the xml for custom layout for ShowCaseView to use when default one won't do his job (text go off from the screen, button not there where it should be and etc.)
showcase_text.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/scvShowCase" >
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/welcome"
android:id="@+id/tvSvTitle"
android:layout_gravity="center_horizontal"
android:layout_marginTop="50dp"
android:textColor="?attr/color_7"
android:textSize="@dimen/h1_size"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/welcome_text"
android:id="@+id/tvSvDetailText"
android:layout_gravity="center_horizontal"
android:textColor="?attr/color_4"
android:layout_marginTop="30dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:textSize="@dimen/text_normal_size"
android:gravity="center" />
</LinearLayout>
</ScrollView>
</FrameLayout>
As to cbActivity.BoolFromPref(getLocalClassName(), false)
- I use shared preferences to check whether or not this Activity has been started, so this line checks this value, also in Fragment's code you see blocking all views of layout while presentation, if you don't need it - don't call that.
If you need to use custom view, you add "true" when creating a Target
like this:
svElements.add(new xSchowCaseTarget(Target.NONE, getString(R.string.welcome), getString(R.string.welcome_text), position.FILL_BOTTOM, true));
And the last thing is, the cbActivity - mybase class for Activities, I use it here as reference to the common methods and vars, so the position enum is declared in that class, and it looks like:
public enum position {TOP_RIGHT, TOP_LEFT, BOTTOM_RIGHT, BOTTOM_LEFT, CENTER, BOTTOM_CENTER, CENTER_TOP, FILL_BOTTOM, FILL_TOP}
Here is an example of how I call ShowcaseView from Activities:
if (cbActivity.BoolFromPref(getLocalClassName(), false)) {
ArrayList<xSchowCaseTarget> svElements = new ArrayList<xSchowCaseTarget>();
svElements.add(new xSchowCaseTarget(Target.NONE, getString(R.string.welcome), getString(R.string.welcome_text), position.FILL_BOTTOM, true));
svElements.add(new xSchowCaseTarget(new ViewTarget(R.id.xxx, ActMain.this), getString(R.string.xxx), getString(R.string.xxx), position.BOTTOM_LEFT));
svElements.add(new xSchowCaseTarget(new ViewTarget(R.id.xxx, ActMain.this), getString(R.string.xxx), getString(R.xxx), position.BOTTOM_RIGHT));
if (isThereActionMenuButton())
svElements.add(new xSchowCaseTarget(new ActionViewTarget(ActMain.this, ActionViewTarget.Type.OVERFLOW), getString(R.string.xxx), getString(R.string.xxx), position.FILL_BOTTOM));
svElements.add(new xSchowCaseTarget(new ViewTarget(R.id.xxx, ActMain.this), getString(R.string.xxx), getString(R.string.xxx), position.CENTER));
frShowCase frSC = frShowCase.newInstance(svElements);
fm.beginTransaction().add(frSC , "xxx").commit();
}