MonoDroid.Dialog DoubleButton cell - android

I am trying to create a cell which has 2 buttons side by side.
I have done this in MT.D : How can I get an element with 2 buttons side by side?
I now need to do this for the droid version.
Looking at the source for ButtonElement in the MvvmCross code I can see that Element has consideration for 1 click event only.
What is the best way of going about this for MD.D? It looks completely different (obviously) to the touch counterpart.
I can create a layout that has the 2 buttons in but I have no way of hooking the buttons up to click events.
Here is the layout code (dialog_double_button.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/LinearLayout02"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_alignParentBottom="true">
<Button
android:id="#+id/Button02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" android:text="button 1">
</Button>
<Button
android:id="#+id/Button03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="button 2">
</Button>
</LinearLayout>
And my element looks like :
public class DoubleButton : Element, View.IOnClickListener
{
public DoubleButton (): base("", "dialog_double_button")
{
}
protected override View GetViewImpl (Context context, ViewGroup parent)
{
var view = DroidResources.LoadButtonLayout(context, parent, LayoutName);
if (view != null)
{
var buttons = view.FindViewById<Button> (Resource.Layout.dialog_double_button);
}
return view;
}
public void OnClick(View v)
{
if (Click != null)
Click(this, EventArgs.Empty);
if (SelectedCommand != null)
{
// TODO should we have a SelectedCommandParameter here?
if (SelectedCommand.CanExecute(null))
{
SelectedCommand.Execute(null);
}
}
}
}
When I run this code with:
[Activity(Label = "Login")]
public class Login : MvxDialogActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Root = new RootElement{
new Section{
new DoubleButton()
}
};
}
}
I can see the layout is added to the UI but inside my elements c# code calling var buttons = view.FindViewById<Button> (Resource.Layout.dialog_double_button); yields nothing - so I can't hook the click events up.
Any ideas?

view.FindViewById will only work if view its the parent of that buttons. In your case it is not, it's the parent of "LinearLayout02", so you should get it first and use FindViewById on it.
(OP amending this answer as it was nearly what I ended up with)
I actually fixed it using:
var button1 = view.FindViewById<Button>(context.Resources.GetIdentifier("Button02", "id", context.PackageName));
var button2 = view.FindViewById<Button>(context.Resources.GetIdentifier("Button03", "id", context.PackageName));

Related

Add custom layout to ConstraintLayout programmatically

Good day everyone.
I'm trying to a layout to a ConstraintLayout in a for-loop.
The layout is decalred as follows:
public class SingleMeal extends ConstraintLayout {
private TextView food_id;
private ImageButton spacer_minus;
private ImageButton spacer_plus;
private TextView food_quantity;
public SingleMeal(Context context) {
super(context);
init();
}
private void init(){
inflate(getContext(), R.layout.activity_single_meal, this);
this.food_id = findViewById(R.id.food_id);
this.spacer_minus = findViewById(R.id.spacer_minus);
this.spacer_plus = findViewById(R.id.spacer_plus);
this.food_quantity = findViewById(R.id.food_quantity);
}
public void setFood_id(String food_id) {
this.food_id.setText(food_id);
}
public TextView getFood_quantity() {
return food_quantity;
}
public ImageButton getSpacer_minus() {
return spacer_minus;
}
public ImageButton getSpacer_plus() {
return spacer_plus;
}
}
The xml of the layout is as follows:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".selectMeals.SingleMeal">
<TextView
android:id="#+id/food_id"
android:layout_width="wrap_content"
android:layout_height="#dimen/edit_text_height"
android:layout_marginStart="#dimen/medium_space"
android:gravity="center"
android:textSize="#dimen/text_size"
android:layout_alignParentStart="true"/>
<LinearLayout
android:id="#+id/layout_food_quantity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="#dimen/medium_space"
android:orientation="horizontal"
android:layout_alignParentEnd="true">
<ImageButton
android:id="#+id/spacer_minus"
android:layout_width="#dimen/plus_minus"
android:layout_height="#dimen/plus_minus"
android:background="#drawable/minus"
android:contentDescription="#string/spacer"/>
<TextView
android:id="#+id/food_quantity"
android:layout_width="#dimen/info_quantity"
android:layout_height="#dimen/edit_text_height"
android:gravity="center"
android:text="0"
android:singleLine="true"
android:textSize="#dimen/text_size" />
<ImageButton
android:id="#+id/spacer_plus"
android:layout_width="#dimen/plus_minus"
android:layout_height="#dimen/plus_minus"
android:background="#drawable/plus"
android:contentDescription="#string/spacer"/>
</LinearLayout>
</RelativeLayout>
On the main activity I'm creating a new SingleMeal object, and populate it it's methods.
ConstraintLayout previousCourse = null;
for (Course course : meal.getCourses()) {
final SingleMeal food_container = new SingleMeal(this);
food_container.setId(View.generateViewId());
food_container.setFood_id(course.getName());
final TextView food_quantity = food_container.getFood_quantity();
ImageButton minus = food_container.getSpacer_minus();
minus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String foodQuantity = food_quantity.getText().toString();
int foodQuantityInt = Integer.parseInt(foodQuantity) > 0 ? Integer.parseInt(foodQuantity) - 1 : Integer.parseInt(foodQuantity);
food_quantity.setText(String.valueOf(foodQuantityInt));
}
});
ImageButton plus = food_container.getSpacer_plus();
plus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String foodQuantity = food_quantity.getText().toString();
int foodQuantityInt = Integer.parseInt(foodQuantity) + 1;
food_quantity.setText(String.valueOf(foodQuantityInt));
}
});
lunchCountainer.addView(food_container);
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(lunchCountainer);
if (previousCourse == null)
constraintSet.connect(food_container.getId(), ConstraintSet.TOP , findViewById(R.id.txt_menu_date).getId(), ConstraintSet.BOTTOM,0);
else
constraintSet.connect(food_container.getId(), ConstraintSet.TOP , previousCourse.getId(), ConstraintSet.BOTTOM,0);
constraintSet.applyTo(lunchCountainer);
previousCourse = food_container;
}
I'm probably doing something very wrong as it goes trough the loop without any error, but it is not showing anything in the end.
The lunchContainer as previously said is a ConstraintLayout (inside a ScrollView):
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/lunch_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|center_vertical"
android:isScrollContainer="true"
android:orientation="vertical"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical" />
Any idea?
It seems like you don't want a ConstraintLayout here, if you are stacking the items vertically I would suggest a LinearLayout set to Vertical.
Set the width of each item to MATCH_PARENT, then set the layout weight to be the same on each item, but make sure the height is set to WRAP_CONTENT so the sizes are the same for each item.
Not 100% sure this will work but this is the way to do it.
Or you could use a ListView, with your items within that, this will also handle scrolling etc for you.
Either option will work for you.

Android Custom ListView Rows: Text Style not being applied

Trying to create custom rows in my listview (to look like this). I've created a custom row layout & derived adapter class. The data loads and shows fine, but the text is not using any format/style specified in my custom row .xml layout file. It's all just the default size/weight, etc.
Here's the custom row layout (listview_desc.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#222222">
<TextView
android:id="#+id/name"
android:text="Name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_margin="10dip"
android:textStyle="bold"
android:textSize="20dip"
/>
<TextView
android:id="#+id/description"
android:text="Description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_margin="10dip"
android:textSize="13dip" />
</LinearLayout>
Here's my main layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:theme="#android:style/Theme.NoTitleBar"
android:minWidth="25px"
android:minHeight="25px"
android:background="#drawable/gradient_darkbg">
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/listView1" />
</LinearLayout>
My adapter code (I'm using Xamarin, but I don't think that's the problem...)
public class ListViewFormAdapter : BaseAdapter<Form>
{
List<Form> mForms;
Activity context;
public ListViewFormAdapter(Activity context, List<Form> items)
: base()
{
this.context = context;
this.mForms = items;
}
public override long GetItemId(int position)
{
return position;
}
public override Form this[int position]
{
get { return mForms[position]; }
}
public override int Count
{
get { return mForms.Count; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = mForms[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = context.LayoutInflater.Inflate(Resource.Layout.listview_desc, null);
view.FindViewById<TextView>(Resource.Id.name).Text = item.Name;
view.FindViewById<TextView>(Resource.Id.description).Text = item.Description;
return view;
}
}
And finally the main activity where I load and use the adapter:
public class HomeScreenActivity : Activity
{
List<Form> mForms;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Create your application here
SetContentView (Resource.Layout.Home);
// Load all forms and populate the main menu
mForms = Utils.FormLoader.LoadForms("Forms");
ListView listView = FindViewById<ListView>(Resource.Id.listView1);
listView.Adapter = new ListViewFormAdapter(this, mForms);
}
}
Sorry for all the code, maybe it'll help someone in the future... thanks for any help.
I'm not sure that this is the problem, but you inflating the views incorrectly. it should be
view = inflater.inflate(R.layout.listview_desc, parent, false);
instead of
view = context.LayoutInflater.Inflate(Resource.Layout.listview_desc, null);
using the 3 parameter version of inflate
What styles aren't showing correctly? I'm not sure what you're expecting or what you're seeing from the question. If it is to do with alignment, you should bear in mind that android:layout_alignParentLeft="true" is not valid in a LinearLayout
Thanks for the response guys. Turns out it was some problem with Git/Xamarin. I committed my sources at another machine, came home, synced up and all my formatting in the row layout xml were gone. Who knows... maybe a cached version was being used or something. I actually had to use the code posted on this page to get it to work (since it was lost), so maybe someone can use this as example code. It works.

Android setError() message scrolling on top of ActionBar

My issue is that the error message in my EditTexts are scrolling on top of the action bar. Is this an android bug, or am I doing something wrong?
Also this bug happens even when the keyboard is down, it just happens to be up in the screenshots.
Here is what I am talking about: http://imgur.com/fG8bd3E,uFzhOXa#1 <- there are two images
Here is my layout, I add the EditTexts in my code to the kiosk_form_table LinearLayout
<ScrollView
style="#style/DefaultBackground"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:fadeScrollbars="false"
android:padding="20dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingRight="20dp" >
<LinearLayout
android:id="#+id/kiosk_form_table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<Button
android:id="#+id/kiosk_submit_large"
style="#style/LoginButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:onClick="submit"
android:text="#string/submit" />
</LinearLayout>
</ScrollView>
How I add the EditTexts
kiosk_form.addView(getKioskRow(R.layout.kiosk_text_row, "First Name", true, null));
private View getKioskRow(int layout, String header, boolean required, String buttonName)
{
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(layout, null);
view.setTag(required);
addHeader((TextView) inflater.inflate(R.layout.field_header, null), header);
if (required)
((TextView) view.findViewById(R.id.kiosk_input)).setHint("Required");
if (buttonName != null)
((Button) view.findViewById(R.id.kiosk_input_button)).setText(buttonName);
return view;
}
private void addHeader(TextView view, String header)
{
view.setTag(false);
view.setText(header);
kiosk_form.addView(view);
}
How I set the error
(TextView) view).setError(getString(R.string.error_field_required));
It is Android OS bug.
You can track its progress here
I had the same problem. Solved it like this:
private void processingErrorPopupsWhenScrolling(Rect scrollBounds, TextInputEditText... views) {
boolean isViewInFocus = false;
for (TextInputEditText textInputEditText : views) {
if (textInputEditText.getError() != null) {
if (textInputEditText.getLocalVisibleRect(scrollBounds)) {
textInputEditText.setVisibility(View.VISIBLE);
if (!isViewInFocus) {
textInputEditText.requestFocus();
isViewInFocus = true;
}
} else {
textInputEditText.setVisibility(View.INVISIBLE);
}
}
}
}
// in onCreate(){
Rect scrollBounds = new Rect();
mScrollView.getHitRect(scrollBounds);
mScrollView.getViewTreeObserver().addOnScrollChangedListener(() ->
processingErrorPopupsWhenScrolling(scrollBounds,
mLink,
mTitle,
mPrice)
);}
I resolve similiar problem by setting flag
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
Where do you want to see the error message? If you want it on EditText, set it on editText.
((EditText) findViewByID(R.id.my_edit_text)).setError ...... // and so on
Edit: original answer didn't help.
Here's one possible solution: you can hide the error message when the user is scrolling the view. When the scroll has finished you can re-set the error message and it should appear in the right spot! Here's how you can detect when a scroll finished:
Android: How to detect when a scroll has ended

View over Canvas Visibility issue

I have this layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.components.game.GameView
android:id="#+id/game_id"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:id="#+id/ChatLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="invisible"
android:focusable="true"
android:focusableInTouchMode="true" >
<Button
android:id="#+id/ChatCancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="X" />
<Button
android:id="#+id/ChatOkButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="OK" />
<EditText
android:id="#+id/ChatEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#+id/ChatOkButton"
android:layout_toRightOf="#+id/ChatCancelButton"
android:maxLength="50"
android:singleLine="true" />
</RelativeLayout>
</RelativeLayout>
It's a RelativeLayout over a canvas. At start time it's invisible but when a user clicks a button the layout should become visible.
The problem is that it's not becoming visible. The layout is there but it's just not drawing it. If I press the position where the layout should appear it receives the event and opens the keyboard but it's not drawing the whole layout.
What is the problem?
If I set the RelativeLayout to visible at the beginning it works fine. it shows the layout and if I toggle between invisible and visible it works fine.
I made a workaround that almost always works.
I start the layout visible and than do that in the oncreate:
chatLayout.postDelayed(new Runnable() {
#Override
public void run() {
chatLayout.setVisibility(View.INVISIBLE);
}
}, 50);
But I don't like it and want to understand what's the problem.
The code:
It starts from a canvas button which send a message to a handler:
public void showInputLayout() {
Message.obtain(gameHandler, SHOW_INPUT_LAYOUT).sendToTarget();
}
In the handler:
case SHOW_INPUT_LAYOUT:
gameActivity.setChatVisibility(true);
break;
setChatVisibility:
public void setChatVisibility(boolean isVisible) {
int visible = isVisible ? View.VISIBLE : View.INVISIBLE;
chatLayout.setVisibility(visible);
if(isVisible){
chatEditText.setFocusable(true);
chatEditText.requestFocus();
}
}
Add a click listener to RelativeLayout and switch the visibility between GONE and VISIBLE. Try something like this:
int visibility = View.VISIBLE;
RelativeLayout layout = (RelativeLayout)findViewById(R.id.ChatLayout);
layout.setVisibility(visibility);
layout.setOnClickListener(new View.OnClickListener{
public void onClick(View v)
{
if(visibility == View.VISIBLE)
visibility = View.GONE;
else
visibility = View.VISIBLE;
v.setVisibility(visibility);
}
})
I ran into a similar issue recently, and for my case the problem was actually in the onDraw() method of the view underneath (should be com.components.game.GameView in your case). See if you can add calls to Canvas' getSaveCount(), save() and restoreToCount() in your drawing code, similar to this:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int saveCount = canvas.getSaveCount();
canvas.save();
// custom drawing code here ...
// use Region.Op.INTERSECT for adding clipping regions
canvas.restoreToCount(saveCount);
}
I believe what happened was that sometimes the framework set the clipping regions for the elements on top of our Canvas-drawing widget before our onDraw() method is called so we need to make sure that those regions are preserved.
Hope this helps.

How to use the xml setting in a view of a activity?

I want to show two views in one activity. If I clicked on button in the first view I want to see the second and other way round.
The views should not have the same size as the screen so I want e.g. to center it, like you see in first.xml.
But if I add the views with
addContentView(mFirstView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
the views are not centered. They are shown at top left.
How can I use the xml settings to e.g. center it?
first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:background="#drawable/background"
android:layout_gravity="center"
android:minWidth="100dp"
android:minHeight="100dp"
android:paddingBottom="5dp"
>
<LinearLayout android:id="#+id/head"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton android:id="#+id/first_button"
android:src="#drawable/show_second"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null" />
</LinearLayout>
second.xml same as first.xml but with
<ImageButton android:id="#+id/second_button"
android:src="#drawable/show_first"
... />
ShowMe.java
public class ShowMe extends Activity {
View mFirstView = null;
View mSecondView = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initFirstLayout();
initSecondLayout();
showFirst();
}
private void initFirstLayout() {
LayoutInflater inflater = getLayoutInflater();
mFirstView = inflater.inflate(R.layout.first, null);
getWindow().addContentView(mFirstView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
ImageButton firstButton = (ImageButton)mMaxiView.findViewById(R.id.first_button);
firstButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ShowMe.this.showSecond();
}
});
}
private void initSecondLayout() {
// like initMaxiLayout()
}
private void showFirst() {
mSecondView.setVisibility(View.INVISIBLE);
mFirstView.setVisibility(View.VISIBLE);
}
private void showSecond() {
mFirstView.setVisibility(View.INVISIBLE);
mSecondView.setVisibility(View.VISIBLE);
}}
Hope someone can help.
Thanks
Why don't you use setContentView(R.layout.yourlayout)? I believe the new LayoutParams you're passing in addContentView() are overriding those you defined in xml.
Moreover, ViewGroup.LayoutParams lacks the layout gravity setting, so you would have to use the right one for the layout you're going to add the view to (I suspect it's a FrameLayout, you can check with Hierarchy Viewer). This is also a general rule to follow. When using methods that take layout resources as arguments this is automatic (they might ask for the intended parent).
With this consideration in mind, you could set your layout params with:
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(/* wrap wrap */);
lp.setGravity(Gravity.CENTER);
addContentView(mYourView, lp);
But I would recommend setContentView() if you have no particular needs.
EDIT
I mean that you create a layout like:
~~~/res/layout/main.xml~~~
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="....."
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
then in your onCreate() or init...Layout():
setContentView(R.layout.main);
FrameLayout mainLayout = (FrameLayout)findViewById(R.id.mainLayout);
// this version of inflate() will automatically attach the view to the
// specified viewgroup.
mFirstView = inflater.inflate(R.layout.first, mainLayout, true);
this will keep the layout params from xml, because it knows what kind it needs. See reference.

Categories

Resources