How do I show a progress dialog on Android without blocking clicks on the other UI elements on the screen (like Ads) ?
public void addProgressBar(Activity activity){
final ViewGroup rootFrameLayout = (ViewGroup) activity.getWindow().peekDecorView();
final ViewGroup modal = new RelativeLayout(activity);
ProgressBar progressBar = new ProgressBar(activity);
LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
modal.addView(progressBar, layoutParams);
rootFrameLayout.addView(modal, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
rootFrameLayout.invalidate();
}
You have to use ProgressBar view, and create a separate overlay for the progress bar.
The most transparent way would be to create an abstract Activity and override the setContentView() method (both with id, and View, shown only with id). Than you can inherit your Activities from this one, and use it as a normal Activity with the added benefit of showProgress and hideProgress methods.
private HashMap<View, ProgressBar> progressBars = new HashMap<View, ProgressBar>();
private RelativeLayout overlay;
public void setContentView(int id) {
FrameLayout combinedView = new FrameLayout();
combinedView.setLayoutParams(new ViewGroup.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
View background = getLayoutInflater().inflate(id, null);
background.setLayoutParams(new ViewGroup.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
combinedView.addView(background);
overlay = new RelativeLayout();
overlay.setLayoutParams(new ViewGroup.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
combinedView.addView(overlay);
super.setContentView(combinedView);
}
public void showProgress(View view) {
ProgressBar progressBar = progressBars.get(view);
if (progressBar == null) {
progressBar = new ProgressBar();
progressBars.put(view, progressBar);
progressBar.setLayoutParams(new ViewGroup.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
overlay.addView(progressBar);
}
int[] position = view.getLocationOnScreen();
int width = view.getWidth();
int height = view.getHeight();
int progressWidth = progressBar.getWidth();
int progressHeight =progressBar.getHeight();
progressBar.setMargins(position[0] + width / 2 - progressWidth/2,
position[1] + height / 2 - progressHeight/2,0,0);
progressBar.setVisibility(View.VISIBLE);
}
public void hideProgress(View view) {
ProgressBar progressBar = progressBars.get(view);
if (progressBar != null) {
progressBar.setVisibility(View.INVISIBLE);
}
}
You can create a completely transparent Linear or any other kind of layout with a ProgressBar in center and add this layout in a FrameLayout which contain all your other controls. Now when you want to show the progress bar make this layout visible and make invisible when you do not want it to show.
bankings method I felt was the best and the simplest to implement. Just for the convenience of anybody wanting to use it, rather make the method return ProgressBar and when you want to remove this progress bar, you can use this return value to just set its visibility to gone as shown for example
progressBar.setVisibility(View.GONE);
Hope it adds value to the above answers.
When a dialog appears, it adds a layer to underlaying view blocking all events on it.
To achieve what you are looking for, you can create a view similar to dialog view and show it instead of dialog. For dialogs and transparent background activity, your target won't be achieved.
#banking's method is sweet and short, I have modified it a little to use with layout file instead of creating it with Java code:
progress_spinner.xml: (in layout folder)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<ProgressBar
android:id="#+id/ProgressBar"
style="?android:attr/progressBarStyleInverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</RelativeLayout>
Java:
ProgressBar progressBar=null;
public void addProgressBar(Activity activity) {
ViewGroup rootFrameLayout = (ViewGroup) activity.getWindow().peekDecorView();
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View progressModal = inflater.inflate(R.layout.progress_spinner, rootFrameLayout, false);
rootFrameLayout.addView(progressModal, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
rootFrameLayout.invalidate();
progressBar = (ProgressBar) progressModal.findViewById(R.id.ProgressBar);
}
public void hideProgressBar() {
if (progressBar != null)
progressBar.setVisibility(View.INVISIBLE);
}
public void showProgressBar() {
if (progressBar != null)
progressBar.setVisibility(View.VISIBLE);
}
Related
I'm trying to create a view that contains TextView (on the left) and Button (on the right) and a SeekBar at the Bottom, something like this.
|-----------------------------------|
| <TextView> <Button> |
| < SeekBar > |
|-----------------------------------|
Note that angle brackets represents the width, just used for demonstration.
I can do that by creating a CompoundView but I wanted to keep things flat.
I'm going to create others similar to this one and there will be a lot of these.
Please ask for any further clarifications (if needed).
Thank you.
What about using a Framelayout and adding your views on the go?
public class Cell extends FrameLayout {
private TextView tv;
private Button btn;
private ProgressBar progressBar;
public Cell (Context context, int width, int height) {
super(context);
getLayoutParams().width = width;
getLayoutParams().height = height;
tv = new TextView(context);
FrameLayout.LayoutParams tvParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.TOP|Gravity.LEFT);
tv.setLayoutParams(tvParams);
btn = new Button(context);
FrameLayout.LayoutParams btnParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.TOP|Gravity.RIGHT);
btn.setLayoutParams(btnParams);
progressBar = new ProgressBar(context);
FrameLayout.LayoutParams progressParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM);
progressBar.setLayoutParams(progressParams);
addView(tv);
addView(btn);
addView(progressBar);
}
public void setText (String text) {
tv.setText(text);
}
public void setProgress (int progress) {
progressBar.setProgress(progress);
}
}
Note that you might need to use other constructors as well.
I need to do two things with a view:
Move top dimension to the very top of the window
Move bottom dimension to the very bottom of the window.
In short, I need the view to cover 100% of the parent view.
Translation animation didn't work because it moves the view but it doesn't increase the size.
Scale animation works but it stretches the content of the view and I don't want that. I want to increase the visible area, not stretch the content to fit the new dimensions.
What's the correct way to do this?
That can be easily achieved with Transitions API.
With Transitions API you do not take care of writing animations, you just tell what you want the end values be and Transitions API would take care of constructing animations.
Having this xml as content view (a view in the center of the screen):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="#+id/view"
android:layout_width="120dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:background="#color/colorAccent" />
</FrameLayout>
In activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.item)
val root = findViewById(R.id.root) as ViewGroup
val view = findViewById(R.id.view)
view.setOnClickListener {
// After this line Transitions API would start counting the delta
// and will take care of creating animations for each view in `root`
TransitionManager.beginDelayedTransition(root)
// By default AutoTransition would be applied,
// but you can provide your transition with the second parameter
// val transition = AutoTransition()
// transition.duration = 2000
// TransitionManager.beginDelayedTransition(root, transition)
// We are changing size of the view to match parent
val params = view.layoutParams
params.height = ViewGroup.LayoutParams.MATCH_PARENT
params.width = ViewGroup.LayoutParams.MATCH_PARENT
view.requestLayout()
}
}
Here's the output:
Platform's Transitions API (android.transition.TransitionManager) is available from API 19, but support libraries backport the functionality upto API 14 (android.support.transition.TransitionManager).
I like to keep everything as simple as it can be.
so my suggestion would be using a android Animating Layout Changes
Here is a sample:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:animationCache="true">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:background="#color/colorPrimary"
android:layout_gravity="center" />
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
}
#Override
protected void onResume() {
super.onResume();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
View view = getWindow().getDecorView();
int height = getWindow().getDecorView().getHeight();
int width = getWindow().getDecorView().getWidth();
textView.setLayoutParams(new LinearLayout.LayoutParams(width, height));
LayoutTransition layoutTransition = ((ViewGroup) textView.getParent()).getLayoutTransition();
layoutTransition.enableTransitionType(LayoutTransition.CHANGING);
}
}, 2000);
}
}
You can try using ValueAnimator as shown in this answer:
https://stackoverflow.com/a/32835417/3965050
Note: I wanted to write this as a comment, but I don't have the reputation. This should not be considered as a full answer.
animateLayoutChanges="true" in the parent xml
+
.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
does the trick most of the times and it won't stretch the existing child views
Using ConstraintLayout with ConstrainSet should match your need in the most efficient way.
public class MainActivity extends AppCompatActivity {
ConstraintSet mConstraintSet1 = new ConstraintSet(); // create a Constraint Set
ConstraintSet mConstraintSet2 = new ConstraintSet(); // create a Constraint Set
ConstraintLayout mConstraintLayout; // cache the ConstraintLayout
boolean mOld = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = this;
mConstraintSet2.clone(context, R.layout.state2); // get constraints from layout
setContentView(R.layout.state1);
mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main);
mConstraintSet1.clone(mConstraintLayout); // get constraints from ConstraintSet
}
public void foo(View view) {
TransitionManager.beginDelayedTransition(mConstraintLayout);
if (mOld = !mOld) {
mConstraintSet1.applyTo(mConstraintLayout); // set new constraints
} else {
mConstraintSet2.applyTo(mConstraintLayout); // set new constraints
}
}
}
Source https://developer.android.com/reference/android/support/constraint/ConstraintSet.html
All you need is to define a second layout.xml with your expanded constraints and apply the second ConstraintSet to your view or activity when necessary.
ValueAnimator anim = ValueAnimator.ofInt(viewToIncreaseHeight.getMeasuredHeight(), -100);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = viewGroup.getLayoutParams();
layoutParams.height = val;
viewGroup.setLayoutParams(layoutParams);
}
});
anim.setDuration(DURATION);
anim.start();
I have been trying many commands to setup the size of my DialogFragment. It only contains a color-picker, so I have removed the background and title of the dialog:
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(
new ColorDrawable(android.graphics.Color.TRANSPARENT));
However I also want to position the dialog where I want and it is problematic. I use:
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = LayoutParams.WRAP_CONTENT;
params.height = LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.LEFT;
getDialog().getWindow().setAttributes(params);
But one (big) obstacle remains: even though my dialog pane is invisible, it still has a certain size, and it limits the positions of my dialog. The LayoutParams.WRAP_CONTENT are here to limit the size of this pane to my color-picker, but for some reason it does not work.
Has anyone been able to do something similar?
i met a similar question that is you can't set the dialogFragment's width an height in code,after several try ,i found a solution;
here is steps to custom DialogFragment:
1.inflate custom view from xml on method
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().setCanceledOnTouchOutside(true);
View view = inflater.inflate(R.layout.XXX,
container, false);
//TODO:findViewById, etc
return view;
}
2.set your dialog's width an height in onResume(),remrember in onResume()/onStart(),seems didn't work in other method
public void onResume()
{
super.onResume();
Window window = getDialog().getWindow();
window.setLayout(width, height);
window.setGravity(Gravity.CENTER);
//TODO:
}
After some trial and error, I have found the solution.
here is the implementation of my DialogFragment class :
public class ColorDialogFragment extends SherlockDialogFragment {
public ColorDialogFragment() {
//You need to provide a default constructor
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_color_picker, container);
// R.layout.dialog_color_picker is the custom layout of my dialog
WindowManager.LayoutParams wmlp = getDialog().getWindow().getAttributes();
wmlp.gravity = Gravity.LEFT;
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_FRAME, R.style.colorPickerStyle);
// this setStyle is VERY important.
// STYLE_NO_FRAME means that I will provide my own layout and style for the whole dialog
// so for example the size of the default dialog will not get in my way
// the style extends the default one. see bellow.
}
}
R.style.colorPickerStyle corresponds to :
<style name="colorPickerStyle" parent="Theme.Sherlock.Light.Dialog">
<item name="android:backgroundDimEnabled">false</item>
<item name="android:cacheColorHint">#android:color/transparent</item>
<item name="android:windowBackground">#android:color/transparent</item>
</style>
I simply extend a default Dialog style with my needs.
Finally, you can invoke this dialog with :
private void showDialog() {
ColorDialogFragment newFragment = new ColorDialogFragment();
newFragment.show(getSupportFragmentManager(), "colorPicker");
}
For my use case, I wanted the DialogFragment to match the size of a list of items. The fragment view is a RecyclerView in a layout called fragment_sound_picker. I added a wrapper RelativeLayout around the RecyclerView.
I had already set the individual list item view's height with R.attr.listItemPreferredHeight, in a layout called item_sound_choice.
The DialogFragment obtains a LayoutParams instance from the inflated View's RecyclerView, tweaks the LayoutParams height to a multiple of the list length, and applies the modified LayoutParams to the inflated parent View.
The result is that the DialogFragment perfectly wraps the short list of choices. It includes the window title and Cancel/OK buttons.
Here's the setup in the DialogFragment:
// SoundPicker.java
// extends DialogFragment
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(getActivity().getString(R.string.txt_sound_picker_dialog_title));
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View view = layoutInflater.inflate(R.layout.fragment_sound_picker, null);
RecyclerView rv = (RecyclerView) view.findViewById(R.id.rv_sound_list);
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
SoundPickerAdapter soundPickerAdapter = new SoundPickerAdapter(getActivity().getApplicationContext(), this, selectedSound);
List<SoundItem> items = getArguments().getParcelableArrayList(SOUND_ITEMS);
soundPickerAdapter.setSoundItems(items);
soundPickerAdapter.setRecyclerView(rv);
rv.setAdapter(soundPickerAdapter);
// Here's the LayoutParams setup
ViewGroup.LayoutParams layoutParams = rv.getLayoutParams();
layoutParams.width = RelativeLayout.LayoutParams.MATCH_PARENT;
layoutParams.height = getListItemHeight() * (items.size() + 1);
view.setLayoutParams(layoutParams);
builder.setView(view);
builder.setCancelable(true);
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
// ...
});
builder.setPositiveButton(R.string.txt_ok, new DialogInterface.OnClickListener() {
// ...
});
return builder.create();
}
#Override
public void onResume() {
Window window = getDialog().getWindow();
window.setLayout(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
super.onResume();
}
private int getListItemHeight() {
TypedValue typedValue = new TypedValue();
getActivity().getTheme().resolveAttribute(R.attr.listPreferredItemHeight, typedValue, true);
DisplayMetrics metrics = new android.util.DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
return (int) typedValue.getDimension(metrics);
}
Here is fragment_sound_picker:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_sound_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
use this code for resize of Dialog Fragment android
public void onResume() {
super.onResume();
Window window = getDialog().getWindow();
window.setLayout(250, 100);
window.setGravity(Gravity.RIGHT);
}
I'm trying to setup a simple view onto the root of phoneGap but i get black screen.
This is the code of a class to inflate and load from xml:
public TopBar(Context context){
myActivity = (Activity)context;
}
protected View createTopBarView() {
RelativeLayout mainLayout = new RelativeLayout(myActivity);
mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
LayoutInflater inflater = myActivity.getLayoutInflater();
View layout = inflater.inflate(R.layout.top_bar, null);
topBarView = (LinearLayout) layout.findViewById(R.id.linearLayoutTopBar);
/**
* Setting Buttons....
*/
//Adding the View
mainLayout.addView(topBarView);
return mainLayout;
}
The method returns a view, and in a class that extneds droidGap i do:
private void createLayout(){
mainRelative = new RelativeLayout(this);
mainRelative.setBackgroundResource(R.drawable.background);
View topBarView = new TopBar(this).createTopBarView();
mainRelative.setVisibility(View.VISIBLE);
mainRelative.addView(topBarView);
root.addView(mainRelative);
}
This function is called from onCreate, But i get a black screen when running.
Can you try to add
mainLayout.addView(layout);
instead of
mainLayout.addView(topBarView);
I might to help
EDIT:
Have you done this: setContentView(yourLayout, LayoutParams); in onCreate?
Here is my code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
AlertDialog alertChoice = new AlertDialog.Builder(context).create();
alertChoice.setTitle("Title");
alertChoice.setView(ViewDialogScreen("Test"));
alertChoice.show();
}
private View ViewDialogScreen(String strText) {
LinearLayout llay = new LinearLayout(context);
llay.setLayoutParams(new LayoutParams(320, 400));
TextView tv = new TextView(context);
tv.setText(strText);
llay.addView(tv);
return llay;
}
I got the output like the above.
I need to show the AlertDialog in full screen / 95% of the Screen size.
I need to handle more fields in the Dialog.
How do I enable the HorizontalScrollview in the AlertDialog?
to get the scrolling behaviour, add a surrounding ScrollView to your layout, which would make your ViewDialogScreen method to this:
private View ViewDialogScreen(String strText) {
ScrollView scroll = new ScrollView(context);
scroll.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
LinearLayout llay = new LinearLayout(context);
llay.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
TextView tv = new TextView(context);
tv.setText(strText);
scroll.addView(llay);
llay.addView(tv);
return scroll;
}
Now try adding some more fields and it should scroll.
I am not sure this but you can set your own layout for dialog. Refer my answer Android: Dialog dismisses without calling dismiss
If you want to customize an AlertDialog you need to create a Custom Dialog.