Creating a Coach Mark on Android - android

I am trying to create a coach mark for Android.
I want it to be absolutely full screen, and my app has an ActionBar. So, the solution suggested by Commons, which is basically inflate a FrameLayout after setContentView(view); does not work, because the FrameLayout would be below the ActionBar. And I want it full screen.
So, I took a screenshot of my screen and drew some coach marks with photoshop and created a .png file of it. I then load this png file with the following code:
public void onCoachMark(){
final Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialog.setContentView(R.layout.activity_main_coach_mark);
dialog.setCanceledOnTouchOutside(true);
//for dismissing anywhere you touch
View masterView = dialog.findViewById(R.id.parent);
masterView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
preferences.edit().putBoolean("COACH_MARK_MAIN_SHOWN", true).commit();
}
});
dialog.show();
}
This works perfectly on my phone, but as we all know, we have thousands of Android models. With another model, this is how it looks like:
I have tried using the ShowcaseView project but, apparently, it does not work with ActionBar buttons. And I need that.
Can anyone help me with this?

Simply add this to your onCoachMark method:
dialog.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

Just think simply
Step 1: Open your main_activity layout file
Step 2: In the main_activity layout check Root Layout, If the Root Layout not start with FrameLayout, change it to FrameLayout.
Step 3: Converting from other layout to FrameLayout it may cause layout problem, you have to fix it. Step 4: Create another FrameLayout that will overlay top of your existing view.
Example:
<FrameLayout ...>
.....
....
<FrameLayout
android:id="#+id/c_mark"
.../>
</FrameLayout>
Step 5: Position your new FrameLayout by layout gravity. Example: android:layout_gravity="top|right"
Step 6: Hide that view by default
Step 7: Now in your Main Activity use this Id and play with property. Just custom design your c_mark FrameLayout set id and use it. Let me Give you example.
Let me Give you example.
Example: MainActivity.class
FrameLayout coachMarkLayout = findViewById( R.id.c_mark);
coachMarkLayout.setVisibility( View.VISIBLE );
FrameLayout messageBoxLayout = (FrameLayout) rootFrameLayout.getChildAt( 0 );
LinearLayout linearLayout = (LinearLayout) messageBoxLayout.getChildAt( 1 );
Button skipButton = (Button) linearLayout.getChildAt( 0 );
skipButton.setOnClickListener( v -> {
rootFrameLayout.setVisibility( View.GONE );
} );
Button nextButton = (Button) linearLayout.getChildAt( 1 );
nextButton.setOnClickListener( v -> {
rootFrameLayout.setVisibility( View.GONE );
// you can add second coarch mark here
} );
main_activity.xml
<FrameLayout
android:id="#+id/c_mark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:visibility="gone">
<FrameLayout
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginBottom="70dp">
<include layout="#layout/layout_message_box"/>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal">
<include layout="#layout/layout_arrow"/>
</FrameLayout>
</FrameLayout>

Related

How to disable user interaction while ProgressBar is visible in android?

I am using a custom ProgressBar. Now while a task is going on, I am showing the progress bar, but user can still interact with the views and controls.
How do I disable the user interaction on whole view just like a ProgressDialog does , when it is visible.
Do I need to use a transparent view on top of main view and show the progress bar on that view and hide that view once a task is completed.
Or just get the id of my parentView and set it disabled ? But then I won't be able to dim the background, just like what happens when a dialog appears on the view/Activity/Fragment. Right?
I just want to know the way to disallow the user from any interaction while the progressbar is visible.
Thanks
Your question: How to disable the user interaction while ProgressBar is visible in android?
To disable the user interaction you just need to add the following code
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
To get user interaction back you just need to add the following code
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Here is an example:
Note:I am giving you just an example to show how to disable or retain user interaction
Add a progress bar in your xml.Something like this
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/progressBar"
android:visibility="gone"/>
In MainActivity when a button pressed you show the progressbar and disable the user interaction.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mProgressBar.setVisibility(View.VISIBLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
});
}
And when user backPressed you remove the progressbar again retain the user interaction.Something like this
#Override
public void onBackPressed() {
super.onBackPressed();
mProgressBar.setVisibility(View.GONE);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
If you want to add a feature of disable and greyed out display, you need to add in your xml layout file a linear layout that fills the parent. Set its background to #B0000000 and its visibilty to GONE. Then programmatically set its visibility to VISIBLE.
Hope this help!
I have fixed this issue by adding root layout to the ProgressBar.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:clickable="true"
android:gravity="center"
android:visibility="gone"
android:id="#+id/progress">
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"
android:indeterminateTintMode="src_atop"
android:indeterminateTint="#color/primary"/>
</LinearLayout>
Made the root layout clickable
android:clickable="true"
NOTE: In my main view, I had RelativeLayout as root and have added above-mentioned code inside the root layout at the last position (last child).
Hope this helps!!
just set:
android:clickable="true"
in your xml
<ProgressBar...
Only this makes magic!
To extend (pun intended) on the accepted Answer :
When you use kotlin you can use extension functions. That way you have a quick and nice looking method for blocking and unblocking UI.
fun AppCompatActivity.blockInput() {
window.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
fun AppCompatActivity.unblockInput() {
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
fun AppCompatActivity.blockInputForTask(task: () -> Unit) {
blockInput()
task.invoke()
unblockInput()
}
You can use the blocking and unblocking functions in your activity. Also, you can add more functionality like showing a Toast or something.
When using it in a custom view or any other view, you can simply cast the context to activity and use the functions.
Use blockInputForTask to surround simple linear tasks and blockInputand unblockInput when they are needed in different scopes.
You can use blockInputForTask like this:
blockInputForTask {
// Your lines of code
// Can be multiple lines
}
Use document default method progressbar.setCancelable(false)
Make a dialog with transparent background. The issue with getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); is that when app will go in background and come back user will be able to interact with UI components, a lot more handling. So for blocking UI make a transparent dialog and if you want to set time for hide/show. Do this in a runnable thread. So the solution will be
public class TransparentDialogHelper {
private Dialog overlayDialog;
#Inject
public TransparentDialogHelper() {
}
public void showDialog(Context context) {
if (AcmaUtility.isContextFinishing(context)) {
return;
}
if (overlayDialog == null) {
overlayDialog = new Dialog(context, android.R.style.Theme_Panel);
overlayDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED);
}
overlayDialog.show();
}
public void hideDialog() {
if (overlayDialog == null || AcmaUtility.isContextFinishing(overlayDialog.getContext())) {
return;
}
overlayDialog.cancel();
}
}
-------- Timer
Handler handler = new Handler();
handler.postDelayed( () -> {
view.hideProgress();
}, 2000);
Make your parent layout as Relative Layout & add this :
<RelativeLayout ... >
<other layout elements over which prog bar will appear>
<RelativeLayout android:id="#+id/rl_progress_bar"
android:layout_width="match_parent" android:clickable="true"
android:layout_height="match_parent" >
<ProgressBar android:id="#+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateOnly="true"
style="#android:style/Widget.DeviceDefault.ProgressBar"
android:theme="#style/AppTheme.MyProgressBar"
/>
</RelativeLayout>
If you have floating buttons in your UI, they still grab all the focus & remain clickable when the progress bar is visible. for this use : (when your prog bar is visible & re-enable them when you make your prog bar invisible/gone)
fb.setEnabled(false);

Button from other layout not respond

I´m working on two layouts: the main one and another one (a card layout). I included the card layout inside the main layout, with the following code:
<include
android:id="#+id/miPrueba"
layout="#layout/card_product_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:elevation="10dp"
android:layout_margin="15dp"/>
This works fine, but I have buttons in my main layout and I need to use them. When I try to find them, using findViewByIdid from my card layout, I use this code:
View view = LayoutInflater.from(getApplication()).inflate(R.layout.card_product_details, null);
Button prueba = (Buttton) view.findViewById(R.id.buttonId);
prueba.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Toast por defecto", Toast.LENGTH_SHORT).show();
}
});
What I get is nothing, no error, no null pointer exception, nothing. Simple, it does not respond when I click it.
How I can solve it?
Need more of your code but from what you have given the reason you are having this problem is that the card doesn't have the button buttonId
When you are creating
View view = LayoutInflater.from(getApplication()).inflate(R.layout.card_product_details, null);

Android: programmatically adding view to RelativeLayout

In my Android application I have an activity featuring GoogleMaps. In case of notifications etc., I show a popup window. This works all quite fine. However, I also have another activity where I want to display the same information in the same way. The idea is to use the same popup window in the corresponding view (View2). The problem is that in this second activity/view the popup window does not appear and the code seems to crash at group.addView(popup, lp); (no explicit errors though; but I'm sure there's nothing null). I just don't see the essential difference between the two activities/views that might suggest why the popup windows works fine in the in the one view but not in the other. In the following I show the relevant code snippets.
Here is how I instantiate the popup in both activities. The only difference is the third parameter that refers to the ID of the parent view; a RelativeLayout in each case.
// GoogleMaps Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mapview);
[...]
this.popupPanel = new PopupPanel(this, R.layout.popup, R.id.relativeLayoutMap);
[...]
}
// View2 Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view2);
[...]
this.popupPanel = new PopupPanel(this, R.layout.popup, R.id.relativeLayoutView2);
[...]
}
This is the main code for initializing the popup and for displaying. Only the value ''parentViewID'' differs between the activities.
public PopupPanel(Activity activity, int layout, int parentViewID) {
this.activity = activity;
this.viewID = viewID;
ViewGroup parent = (ViewGroup) this.activity.findViewById(parentViewID);
this.popup = activity.getLayoutInflater().inflate(layout, parent, false);
}
public void show(boolean alignTop) {
RelativeLayout.LayoutParams lp=new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
);
lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
ViewGroup group = (ViewGroup) this.activity.findViewById(this.viewID);
group.addView(popup, lp); // this 'crashes' for the View2 activity
group.invalidate();
}
Finally, here are the snippets of the corresponding layouts. In both cases I refer to a RelativeLayout where I want to place my popup.
<? xml version="1.0" encoding="utf-8"?>
<LinearLayout [...]>
<RelativeLayout [...] android:id="#+id/relativeLayoutMap">
<com.google.android.maps.MapView [...]/>
</RelativeLayout>
</LinearLayout>
For activity/view View2:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout [...] android:id="#+id/relativeLayoutView2">
<LinearLayout [...] >
...
</LinearLayout>
<LinearLayout [...] >
...
</LinearLayout>
<ScrollView [...] >
<LinearLayout [...] >
...
</LinearLayout>
</ScrollView>
</RelativeLayout>
Any hints are much appreciated! I know that has been addressed in several question, but my 'problem' is that it basically works. Just only in one activity/view, and not in another. It seems that I miss something rather stupid here.
I figured out the difference, and as expected that it was something rather stupid: I forgot to put the code that displays the panel not within the runOnUiThread. I reallt should have know better by now.
runOnUiThread(new Runnable() {
public void run() {
// code for showing the popup
}
});
One side question: I got on the right track when I put the addView(...) call within a try/catch-block. Without it just hangs up there without throwing an error (in LogCat; I'm using Eclipse). Is there a way that such errors are shown by default? Thanks!

how to have a single activity class for many Image Buttons

I have a footer in all the layouts for a android application.
The footer will have Image buttons like "Help", "Home", this Image buttons directly link to Help class and Home class.
Can I have a one single activity class for all the footer Image buttons.
I tried with
public class FooterItems extends Activity implements OnClickListener {
#Override
public void onClick(View view) {
if(view.getId() == R.id.footerBtnHome)
{
Intent myIntent = new Intent(view.getContext(), MainActivity.class);
startActivityForResult(myIntent, 0);
return;
}
if(view.getId() == R.id.footerBtnFeedback)
{
Intent myIntent = new Intent(view.getContext(), Feedback.class);
startActivityForResult(myIntent, 0);
return;
}
}
}
but I am not getting how to call these in a class... for example the project is having MainActivity class in which I have
ImageButton buttonFeedback = (ImageButton) findViewById(R.id.btnFeedback);
buttonFeedback.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent myIntent = new Intent(view.getContext(), Feedback.class);
startActivityForResult(myIntent, 0);
}
});
When I call Feedback.class with onClick from one Image Button... layout and same footer items appears.
I want to use the generalised FooterItems class so I can have one class for footer and use in every other layout.
I am also using android:onClick="onClick" in xml for Image Buttons for footer only.
But how to call those generalised class FooterItems and make it work.
Looking forward to the reply.
thanks.
I can suggest another variant:
I think, you can add to XML android:onClick, for example:
<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="#string/self_destruct"
android:onClick="selfDestruct" />
And when user click this button, android programm call method selfDistruct. You just have to implement this method. Android tutorial: http://developer.android.com/reference/android/widget/Button.html
What you are asking is not much clear.
You want to have Help, Home, etc. Image Buttons as common to all layouts in your application correct ?
If you click any Image Button, you have to show the layout on top and these buttons also has to appear on screen??
If yes my answer may help you.
You told i will create footer items as one activity, but its not good. I will prefer ViewFlipper in this case. See the layout.
<LinearLayout vertical>
<ViewFlipper id=vf>
<include layout1 />
<include layout2 />
<include layout3 />
</ViewFlipper>
<LinearLayout horizontal>
<ImageButton button1 />
<ImageButton button2 />
<ImageButton button3 />
</LinearLayout>
</LinearLayout>
Initially you will get layout1 and all image buttons on screen. If you want to show layout2 when you click button3 write onClickListener as below.
ViewFlipper vf = (ViewFlipper)findViewById(R.id.vf);
The variable vf is used to change layouts.
button3.setOnClickListener(new View.OnClickListener() {
public void onClick() {
vf.setDisplayChild(1);
}
});
I hope it may help you. Bye.
I am sure you want to implement Footer view with 2 buttons: Help and Home, this should be at bottom of every activities.
If you want to implement a code for once then follow the below steps:
Define a footer layout with 2 buttons, define android:onClick="btnHelp" for help button and android:onClick="btnHome" for home button.
Now you can include this layout inside any activities by using <include>.
Define a base activity with below 2 methods.
Now extends this base activity wherever you implements this footer layout.
public void btnHelpClick(View v)
{
// do your task for Help
}
public void btnHomeClick(View v)
{
// do your task for Home
}

How do I create a button programatically?

I just want to dynamicly add buttons to my Layout when i want to.
The buttons should be like this XML Button:
<Button android:text="Text"
android:gravity="bottom"
android:textSize="10dp"
android:textColor="#FFFFFF"
android:layout_width="wrap_content"
android:background="#drawable/attack1"
android:layout_height="wrap_content"
android:id="#+id/workingButton">
</Button>
.
public class GravityIssueActivity extends Activity
{
LinearLayout layout;
Button newButton;
Button buttonByXml;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//the button in the xml file
buttonByXml = (Button)findViewById(R.id.workingButton);
layout = (LinearLayout)findViewById(R.id.layoutToInsert);
//my new programatically "born" button
newButton = new Button(this);
//Setting the properties as i want
newButton.setText("Text");
newButton.setTextSize(10);
newButton.setTextColor(Color.WHITE);
newButton.setBackgroundResource(R.drawable.attack1);
// Gravity = Bottom !!!!!!!!!!
newButton.setGravity(Gravity.BOTTOM);
// getting the XML buttons params just for case...
newButton.setLayoutParams(new LayoutParams(buttonByXml.getLayoutParams()));
//Adding my new Button to the layout
layout.addView(newButton);
}
}
And here is an image of the results:
How is it possible to became different result when I copy all the attributes?
If you want to create dynamic view (like Button,textview etc) then just use this code and run it in your application.
MyActivity.java://your java file
LinearLayout ll = (LinearLayout)findViewById(R.id.linearLayout1);
Button btn = new Button(this)
btn.setText("My Dynamic Button);
btn.setMinLines(1);
btn.setMaxLines(3);
ll.addView(et);
In XML File:
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignBottom="#+id/TextView01"
android:layout_below="#+id/relativeLayout1"
android:orientation="vertical" >
You can absolutely create buttons in code but it's not considered a best-practice unless you have a good reason for dynamically creating the controls. Check out this post Add an array of buttons to a GridView in an Android application.
Try using
Button b = new Button();
This gives you a View instance that can be added to your current parent activity or fragmnet view. For a full reference of possible settings look at http://developer.android.com/reference/android/widget/Button.html
You can use all the set methods provided by parent views in the object hierarchy.
If you need to align text to the bottom of the button, all you need is:
Button button = ...
//apply required paramteres
button.setGravity(Gravity.BOTTOM);
use below code.you also add other parameters
Button submit=new Button(this);
LinearLayout.LayoutParams params= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(25, 0, 25, 0);
submit.setLayoutParams(params);
submit.setText("Attack");
submit.setTextSize(10);
submit.setTextColor(getResources().getColor(R.color.white));
submit.setBackgroundResource(R.drawable.attack);

Categories

Resources