getWidth for a child view within DialogFragment - java

I have a DialogFragment class named DF.java which uses a linearlayout based layout named DF.xml.
The child elements (again linearlayouts) in DF.xml have their widths set to 0dp and are calculated using weights.
I plan to show the DialogFragment DF from an activity on a button click, which works fine and the DialogFragment loads fine.
Now, when the DialogFragment DF shows up, I need to get the width of one of its child elements (a linearlayout).
I have tried getWidth, getMeaseuredWidth, ViewTreeObserver etc in onCreateDialog but result is always zero.
Code to show DialogFragment
DF dialog = DF.newInstance(context, "DFInstance");
dialog.show(((Activity)context).getFragmentManager(), "DFInstance");
Code within DialogFragment DF.java class
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(context);
View dialog_layout = inflater.inflate(R.layout.dialog_DF,
null);
CurrentDialog = new Dialog(context, R.style.DFTheme);
CurrentDialog.setCanceledOnTouchOutside(true);
CurrentDialog.setContentView(dialog_layout);
CurrentDialog.getWindow().setBackgroundDrawable(
new ColorDrawable(android.graphics.Color.TRANSPARENT));
CurrentDialog.setOnShowListener(new OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
//Tried getting width here using many approaches, Ex:
int Width1 = (((Dialog)dialog).findViewById(R.Id.fieldForWidth)).getWidth();
// Also tried using MeasureSpec here and then getMeasuresWidth
// Also tried adding above code in ViewTreeObserver here.
}
});
Window window = CurrentDialog.getWindow();
window.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
CurrentDialog.show();
return CurrentDialog;
}
But strangely, if I choose against DialogFragment, and I show the Dialog directly from my main activity, then same code returns width value perfectly within onShow, using getWidth().
But I really need to do this via DialogFragment for the sake of code organization.
Any assistance or pointers as to what I am doing wrong here will be really helpful.

To get the width of the child LinearLayout in the DialogFragment, you can use an OnShowListener together with getMeasuredWidth():
final int width;
myDialog.setOnShowListener(new DialogInterface.OnShowListener()
{
#Override
public void onShow(DialogInterface dialog)
{
width = ((Dialog)dialog).findViewById(R.id.field_for_width).getMeasuredWidth());
}
});
This works for a child View (just a plain View as well as a LinearLayout) with width set to match_parent or wrap_content.
Please note that in my test I did not call CurrentDialog.show() in onCreateDialog() but only used the following lines in the Activity code to show the dialog:
DialogFragment mDialog = DF.newInstance("x", "yz");
mDialog.show(getSupportFragmentManager(), "myCurrentDialog");

Related

How to set behaivor to bottom sheet dialog without adding to xml layout?

I want to show a BottomSheetDiyalogFragment dynamically with passing some parameters when a onClick event.
InfoBottomSheetDialogFragment dialog = InfoBottomSheetDialogFragment.newInstance("param1", "param2");
dialog.show(getSupportFragmentManager(), "InfoBottomSheetDialogFragment");
Also, I want to set behaivor to the fragment.
BottomSheetBehavior infoBtSheetBehaivor = BottomSheetBehavior.from(findViewById(R.id.info_bottom_sheet));
infoBtSheetBehaivor.setState(BottomSheetBehavior.STATE_COLLAPSED);
When I include the fragment xml layout on main layout, how to reach it for passing parameters?
Or, when I add the fragment programatically, how to set behaivor it? Interesting situation.
You can add BottomSheetDialogFragment dynamically and set behaivor when setupDialog like this:
In your InfoBottomSheetDialogFragment class:
// Delete onCreate(Bundle savedInstanceState) method for avoiding double inflating.
#SuppressLint("RestrictedApi")
#Override
public void setupDialog(#NotNull Dialog dialog, int style) {
super.setupDialog(dialog, style);
View contentView = View.inflate(getContext(), R.layout.info_bottom_sheet, null);
dialog.setContentView(contentView);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams();
CoordinatorLayout.Behavior behavior = params.getBehavior();
if(behavior instanceof BottomSheetBehavior) {
((BottomSheetBehavior) behavior).setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
}
}
Add dialog dynamically where you want and set parameters:
InfoBottomSheetDialogFragment dialog = InfoBottomSheetDialogFragment.newInstance("param1", "param2");
dialog.show(getSupportFragmentManager(), "InfoBottomSheetDialogFragment");

How to use Databinding with DialogFragment

In my app I have an ElementListFragment of items represented by a code object Element. I've data-bound these elements to the list and they display the correct information.
However, to continue filling in the information in each item I put a button on each element that shows a Dialog with additional fields.
But when the Dialog opens the fields are all blank (where one at least ought to be filled) and any fields I fill don't save the data (and don't effect changes on the list).
Appart from the values not being bound (displayed or written), the application works fine. I've essentially tried multiple variations of the sugestions in this question. Here is the code:
public class ElementDialogFragment extends DialogFragment {
private Element mElement;
private Dialog dialog;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.dialog_element, null);
final DialogSkillelementBinding binding = DialogElementBinding.inflate(LayoutInflater.from(getContext()));
builder.setView(v)
// Add action buttons
.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
//this was just an attempt to make it work
binding.executePendingBindings();
dialog.dismiss();
}
});
TextView Title = v.findViewById(R.id.skill_e_dialog_title);
Title.setText(ResourceLocator.getSkillName(mElement.getSkill()));
dialog = builder.create();
dialog.setContentView(binding.getRoot());
binding.setElement(mElement);
binding.executePendingBindings();
return dialog;
}
}
When debuging I've confirmed that mElement is correctly attributed, however it's also bound to the list shown beneath the dialog. The title is also displayed correctly.
Is there a problem double-binding an object?
Are some of the steps on the function maybe out of order?
Is the DialogBuilder somehow incompatible with databinding?
You should set LyfecycleOwner for your binding class for data updating.
binding.setLifecycleOwner(requireActivity())

Android - how to return to original screen view after setContentView(img)

I have written an app which has a screen view containing a thumbnail that I want to expand to full screen view (with pan and zoom) when I click it.
The large view with pan an zoom works fine, but I want to return to the original view when I click the large image.
final TouchImageView imgBig = new TouchImageView(Dashboard.this);
final ImageView img = (ImageView) findViewById(R.id.graph);
final Bitmap bitmap = result.getImage();
img.setImageBitmap(bitmap);
img.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imgBig.setImageBitmap(bitmap);
imgBig.setMaxZoom(4f);
setContentView(imgBig);
imgBig.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// What do I need to do here to return to original thumbnail screen view?
}
});
}
});
Have tried a number of things without success!
Just the original setContentView(R.layout.main) will set it back.
It might be better to have an ImageView in the layout xml and set its image and show and hide it. Otherwise you are stuck with just one view which may be limiting.
When you do a setContentView its initializing your activity with that content. So if you want to just put something on top of it you could just have a hidden view. In your layout xml code make an image view that sits on top of all the other views. Then set its visibility="gone" so its hidden.
Then in your onClick instead of calling setContentView just set the image bitmap like you do and call imgBig.setVisibility(View.Gone or View.Visible) to show or hide your big image.
Another possibility is to have 2 activities. And call startActivity to show your big image and then finish to go back to the other activity like it was.
Another possibility is to use fragments, but that probably more involved.

Destroy a button that was added programatically multiple times on its click

The title may sound confusing I know, I 'm adding a view everytime I click on a button, composed by a textview and a button. I'm setting every added view an ID with simply view.setID(++i) and every added button (inside the views) an ID simply with button.setID(++n), n starting at 1000, since I won't have more than 1000 added views.
Here's what I got:
public class MainActivity extends AppCompatActivity {
GridLayout gridLayout;
static int i;
static int n = 1000;
private Button theButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridLayout = (GridLayout)findViewById(R.id.gamehistory);
Button b = (Button)findViewById(R.id.Button01);
b.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
theButton = new Button(MainActivity.this);
TextView theText = new TextView(MainActivity.this);
theText.setGravity(Gravity.CENTER_HORIZONTAL);
LinearLayout theLayout = new LinearLayout(MainActivity.this);
theLayout.setOrientation(LinearLayout.VERTICAL);
theLayout.setBackgroundColor(Color.parseColor("#8BAAC3"));
theLayout.setId(++i);
theButton.setId(++n);
theButton.setText(theButton.getId() + "");
theText.setText(theLayout.getId() + "");
theLayout.addView(theButton);
theLayout.addView(theText);
gridLayout.addView(theLayout);
GridLayout.LayoutParams lp = (GridLayout.LayoutParams) theLayout.getLayoutParams();
lp.setMargins(10, 10, 10, 10);
}
});
What I need is when I click on a button that was created, the correspondent view is destroyed, and the next views take one step back feeling the gap in the parent which is a GridLayout
Add this where you are adding views to GridLayout -
theLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gridLayout.removeView(theLayout);
}
});
theButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gridLayout.removeView(theLayout);
}
});
For this , you need to make theLayout final
final LinearLayout theLayout = new LinearLayout(LauncherActivity.this);
The simplest method would be.
View v = gridLayout.findViewById(<some id>);
gridLayout.removeView(v);
However it seems like you may want to consider using a RecyclerView. You can add/remove items from the Adapter and the views will be updated for you.
EDIT
When using A RecyclerView you have to specify two essential components.
RecyclerAdapter - This converts data into views (rows, cards, cells, ect.)
LayoutManger - Most common are LinearLayoutManger and GridLayoutManager which define how the views from the adapter are presented out in relation to one another, and handle scrolling.
There are a few more option additions you can can use if needed.
ItemDecoration - define backgrounds, or overlays for cells. (E.G. draw a gray background for every other view in a list)
ItemTouchHelper - does most of the heavy lifting for swipe (e.g. swipe to delete) and drag (e.g. drag to re-arrange) operations.
I would highly suggest getting familiar with the RecyclerView it should be your goto component when you need to display a list of items on the screen.

Android - TranslateAnimation update dynamically the size of the Layout

I'm trying to do an animation that goes like this:
The context:
I have two EditText's I need that when you click over one, the another one come out from behind the first one. Here you have some pictures to get a image of what I want.
To do this obviously I need a TranslateAnimation in order to move the second EditText from behind the first one.
My approach:
The first thing that I could thought was in use a FrameLayout put the EditText one over another, and then in the onTouch event of the first one do a TranslateAnimation on the second one. The problem with this is that if I have the FrameLayout height in wrap_content then the animation will be invisible to the user. And if I change on runtime the height of the FrameLayout I will leave a void below the first EditText as you can see in this picture:
The second solution that I thought was add one AnimationListener to the TranslateAnimation and in the onAnimationStart method change the height of the FrameLayout. But the problem with this is that the height of the FrameLayout changes too abruptly. I want keep the animation smooth.
My question:
How can I get a smooth animation of the second EditText from behind the first one, changing the height of the FrameLayout as the second EditText moves down?
Thanks!
Update:
I changed the FrameLayout by a RelativeLayout I searched and there's no difference for this case. I tried scale this RelativeLayout that contains both of the EditText with an AnimationScale in order to display the animation smoothly, but didn't work. Here is my code:
protected void expanse() {
Log.d("Accordion", "expandAccordion");
//Translate the top of the second EditText to its bottom
TranslateAnimation translateSecond = new TranslateAnimation(second.getLeft(), second.getLeft(),
second.getTop(), second.getBottom());
translateSecond.setDuration(1000);
//Scale the relative layout to show the both of them
ScaleAnimation scaleContainer = new ScaleAnimation(container.getLeft(), container.getLeft(),
container.getTop(), second.getBottom());
scaleContainer.setDuration(1000);
//At the end of the scaling, change the height of the relative layout
scaleContainer.setAnimationListener(new AnimationListenerAdapter() {
#Override
public void onAnimationEnd(Animation animation) {
RelativeLayout.LayoutParams params = (LayoutParams) container.getLayoutParams();
params.height = second.getBottom();
container.setLayoutParams(params);
super.onAnimationEnd(animation);
}
});
container.startAnimation(scaleContainer);
second.startAnimation(translateSecond);
}
BTW I can guarantee that if I hardcode some large height like 350dp, the animation is displayed correctly.
UPDATE:
I tried moving both, the second EditText and the layout below. This is the code. BTW for another reasons I changed the ListView by a custom ViewPager, this doesn't change anything.
public class MainActivity extends FragmentActivity {
private EditText first;
private EditText second;
private HoboViewPager pager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = (HoboViewPager) findViewById(R.id.pager);
pager.setPageTransformer(true, new RotationPageTransformer());
pager.setAdapter(new SampleAdapter(this, getSupportFragmentManager()));
first = (EditText) findViewById(R.id.location_search_field);
second = (EditText) findViewById(R.id.term_search_field);
first.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
expanseSecondField();
return true;
}
});
}
protected void expanseSecondField() {
TranslateAnimation translateSecondField = new TranslateAnimation(second.getLeft(), second.getLeft(),
second.getTop(), second.getBottom());
translateSecondField.setFillAfter(true);
translateSecondField.setDuration(1000);
TranslateAnimation translateContainer = new TranslateAnimation(pager.getLeft(), pager.getLeft(),
pager.getTop(), pager.getTop() + second.getBottom());
translateContainer.setFillAfter(true);
translateContainer.setDuration(1000);
pager.startAnimation(translateContainer);
second.startAnimation(translateSecondField);
}
}
This didn't work because the TranslateAnimation of the container is executed immediately. The result is the same that when I was trying to change the size of the container at the end of the animation.
How use the 2nd option & try performing two translate animations in tandem: 1 on the EditText, then one on the FrameLayout? Give them both the same exact deltas and duration. This way, the FrameLayout will move down smoothly, then at the end of the animation, change the height of the FrameLayout.
Hope this helps :)

Categories

Resources