Creating a Radio-style Preference - android

I'm trying to create a Radio-style Preference where the user can click an option which is then assigned as the new value of the Preference:
however when I click one option is selects all 3 options:
Here is my layout:
preferences.xml
<Preference
android:layout="#layout/preference_gender"
android:key="seeking"
android:title="Seeking"/>
preference_gender.xml
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/seeking"
android:singleLine="true"
android:padding="10dp"
android:textSize="20sp"
android:textColor="#color/colorIcons"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/male"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/male"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#id/female"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:textSize="#dimen/settings_textSize"
android:text="Male"
android:gravity="center"
android:background="#drawable/settings_gender"
android:padding="#dimen/settings_box_selection_padding"
android:paddingStart="#dimen/button_horizontal_padding"
android:paddingEnd="#dimen/button_horizontal_padding"
android:textColor="#color/colorPrimaryDark"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/female"
app:layout_constraintStart_toEndOf="#+id/male"
app:layout_constraintEnd_toStartOf="#id/both"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:textSize="#dimen/settings_textSize"
android:text="Female"
android:gravity="center"
android:padding="#dimen/settings_box_selection_padding"
android:background="#drawable/settings_gender"
android:paddingStart="#dimen/button_horizontal_padding"
android:paddingEnd="#dimen/button_horizontal_padding"
android:textColor="#color/colorPrimaryDark"/>
<androidx.appcompat.widget.AppCompatTextView
app:layout_constraintStart_toEndOf="#id/female"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="#+id/both"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:textSize="#dimen/settings_textSize"
android:text="Both"
android:gravity="center"
android:padding="#dimen/settings_box_selection_padding"
android:background="#drawable/settings_gender"
android:paddingStart="#dimen/button_horizontal_padding"
android:paddingEnd="#dimen/button_horizontal_padding"
android:textColor="#color/colorPrimaryDark"/>
</androidx.constraintlayout.widget.ConstraintLayout>
So I want to be able to click a textview and then get the value of that in Preference.OnPreferenceClickListener.
Any idea how?
EDIT:
class PreferencesFragment : PreferenceFragmentCompat(), View.OnClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val genderPreference: Preference = findPreference("seeking")!!
val parentView = listView.getChildAt(genderPreference.order)
val childView = parentView.findViewById<TextView>(R.id.male) // NullPointerException
}
override fun onClick(v: View?) {
Log.d(TAG, "clicked") // doesn't log
when (v?.id){
R.id.male -> Log.d(TAG, "male")
}
}
}

That's probably because all three buttons are under one preference item, when you set an OnPreferenceClickListener, it selects the entire preference with the layout you included as a whole.
So, instead of setting an OnPreferenceClickListener you should try getting the parent view and setting the click listeners on these TextViews individually and from there update the preference's value.
Or you can just set the onClick attributes of each TextView in the layout xml file to your desired functions.
To get the View of this preference, you can use something like
View preferenceView = getListView().getChildAt(preference.getOrder());
Or, use the getView method and supply both parameters with null:
View preferenceView = preference.getView(null, null);
If you are using the AndroidX library for preference, then there's no getView method, so the only option would be creating a custom Preference class and deal with the views there:
public class CustomPreference extends Preference {
public CustomPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onBindView(View rootView) {
super.onBindView(rootView);
View myView = rootView.findViewById(R.id.myViewId);
// get your textViews from myView
TextView maleText = myView.findViewById(R.id.male);
...
}
}
Then use it in your preference.xml like this:
<your.package.CustomPreference
android:key="your_key"
android:layout="#layout/your_layout" />

Related

Android setclickable for custom view not work

I need to create a custom view to make a counterfeit button, and what's more, that button's enable or not depends on another checkbox.
I'd like the button stay un-clickable when the checkbox was not be checked, but it seems not work as expected.
The control logic of checkbox was in MainActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.use_so_botton)
val cusBtn = findViewById<CusButton>(R.id.cus_btn_in_use)
val chkBox = findViewById<CheckBox>(R.id.check_box_in_use)
chkBox.setOnCheckedChangeListener{
_, isChecked ->
cusBtn.isClickable = isChecked
}
cusBtn.setOnClickListener {
Toast.makeText(this#MainActivity, "Gotta you, custom view", Toast.LENGTH_LONG).show()
}
The layout of MainActivity is simple, named the ConstraintLayout to use_so_botton.xml:
<kot.bignerd.linearlay101.CusButton
android:id="#+id/cus_btn_in_use"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="66dp"
android:layout_marginEnd="66dp"
android:layout_marginStart="66dp"
android:clickable="false"
android:focusable="false"
app:image="#drawable/sun"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:text="Yo haha" />
<CheckBox
android:id="#+id/check_box_in_use"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Use!"
app:layout_constraintTop_toBottomOf="#+id/cus_btn_in_use"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="66dp"
android:layout_marginEnd="66dp"
android:layout_marginStart="66dp"
tools:layout_editor_absoluteX="68dp"
tools:layout_editor_absoluteY="117dp" />
The <kot.bignerd.linearlay101.CusButton tag inside the layout is the custom view's ConstraintLayout xml itself:
<ImageView
android:id="#+id/ImageView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#drawable/budhha"
tools:src="#color/colorPrimary"
>
</ImageView>
<TextView
android:id="#+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
tools:text="Caption of the Image"
android:text="ButtText"
android:gravity="center"
app:layout_constraintStart_toEndOf="#+id/ImageView01"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="#000000">
</TextView>
And the CusButton.kt to get the parameters:
class CusButton(context: Context, attrs: AttributeSet) : ConstraintLayout(context, attrs) {
init {
View.inflate(context, R.layout.so_button, this)
val imageView: ImageView = findViewById(R.id.ImageView01)
val textView: TextView = findViewById(R.id.TextView01)
val attributes = context.obtainStyledAttributes(attrs, R.styleable.CusButton)
imageView.setImageDrawable(attributes.getDrawable(R.styleable.CusButton_image))
textView.text = attributes.getString(R.styleable.CusButton_text)
attributes.recycle()
}
}
Right now, even if the checkbox was unchecked, we could still click the button and got a toast.
I was wondering how to disable the counterfeit button until the checkbox was checked.
The answer to this problem is simply view.setEnabled(true);
Explanation:
For enabling Clicks and Touch events on any view
To Enable Click Listener Response
myView.setClickable(true);
<MyView
...
android:clickable="true"
android:focusable="true">
these attributes are gonna enable "ClickLlistener" Response. for example, Buttons are already set to be pressed and don't need any "setEnabled"
But a Custom View or just a View that isn't set to be Clicked or Touched or Pressed we need 'setEnabled' as true in code
myView.setEnabled(true);
Also, when you write view.setOnClickListener the view automatically is setEnabled(true) but clicks don't work cause it needs setClickable(true) to start listening to the response of click events

Android: How to make Layout clickable when EditText is a child

I have a Relative Layout with an EditText and an ImageView inside it.
Under certain circumstances, I would like to make the whole layout clickable and not any of its children.
I added an OnClickListener on the layout. And I tried the following with the children:
1. setEnabled(false)
2. setClickable(false)
This works for the ImageView but even after the above changes, when I click on the area near the EditText, the keyboard comes up and I can see the cursor in the edit text.
Instead of that, I am hoping that all click/touch events go to the layout.
Could some one help?
Thanks
Yon create a CustomLayout class and override the onInterceptTouchEvent method. If that method returns true, the layout's childrens will not receive the touch event. You can create a member variable and a public setter to change the returning value.
CustomLayout class
public class CustomLayout extends LinearLayout {
//If set to false, the children are clickable. If set to true, they are not.
private boolean mDisableChildrenTouchEvents;
public CustomLayout(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
mDisableChildrenTouchEvents = false;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mDisableChildrenTouchEvents;
}
public void setDisableChildrenTouchEvents(boolean flag) {
mDisableChildrenTouchEvents = flag;
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomLayout layout = findViewById(R.id.mylayout);
//Disable touch events in Children
layout.setDisableChildrenTouchEvents(true);
layout.setOnClickListener(v -> System.out.println("Layout clicked"));
}
}
XML Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.dglozano.myapplication.CustomLayout
android:id="#+id/mylayout"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#drawable/outline"
android:clipChildren="true"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:id="#+id/editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Enter email"
android:inputType="textEmailAddress"
android:layout_gravity="center"/>
</com.example.dglozano.myapplication.CustomLayout>
</android.support.constraint.ConstraintLayout>

Disable EditText OnTouchListener or OnClickListener in custom view

I have a custom View which contains a LinearLayout in turn containing a TextView and and an EditText. When I will try to click on my custom view if I have pressed on the TextView the LinearLayout will receive the click but if I have pressed on the EditText it will not.
Below is a simplified version of my xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="#+id/edt_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#color/md_green_800" />
</LinearLayout>
So when I will press on the EditText I want the parent view (the LinearLayout) to receive the click.
I have tried below code:
private void init(Context context, AttributeSet attrs) {
LayoutInflater inflater = LayoutInflater.from(context);
binding = LayoutHeadingEdittextBinding.inflate(inflater, this, true);
TypedArray array = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.headingtext,
0, 0);
if (attrs != null) {
try {
String hint = array.getString(R.styleable.headingtext_field_hint);
String name = array.getString(R.styleable.headingtext_field_name);
String text = array.getString(R.styleable.headingtext_field_text);
Boolean isFocuable = array.getBoolean(R.styleable.headingtext_field_focus, true);
if (!isFocuable) {
binding.edtTitle.setClickable(false);
binding.edtTitle.setFocusable(false);
binding.edtTitle.setFocusableInTouchMode(false);
binding.edtTitle.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
((View) v.getParent()).performClick();
}
});
// binding.edtTitle.setEnabled(false);
} else {
binding.edtTitle.setClickable(true);
binding.edtTitle.setFocusable(true);
binding.edtTitle.setFocusableInTouchMode(true);
}
binding.edtTitle.setHint(hint);
binding.tvTitle.setText(name);
binding.edtTitle.setText(text);
} finally {
array.recycle();
}
}
}
And this is how i want to use it:
<packagename.customView.HeadingEditText
android:id="#+id/edt_country"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="#string/mobile_or_wechat"
android:onClick="#{()->frag.onCountryClick(countryList)}"
app:field_focus="false"
app:field_hint="#string/country"
app:field_name="#string/country"
app:field_text='#{basicinfo.country_name!=null?basicinfo.country_name:""}'
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/edt_address" />
But it is still not working So i think issue with databinding and click of my customview.
Programatically
//disable click action
editText.setFocusable(false);
editText.setEnabled(false);
//enable click action
editText.setFocusable(true);
editText.setEnabled(true);
xml:
android:focusable="false"
android:enabled="false"
Try this in EditText :
android:focusable="true"
android:focusableInTouchMode="true"
Programatically :
editText.setFocusable(false);
===============EDIT===============
if (!isFocuable) {
binding.edtTitle.setClickable(false);
binding.edtTitle.setFocusable(false);
binding.edtTitle.setFocusableInTouchMode(false);
binding.edtTitle.setOnTouchListener(null);
binding.edtTitle.setOnClickListener(null);
// binding.edtTitle.setEnabled(false);
} else {
binding.edtTitle.setClickable(true);
binding.edtTitle.setFocusable(true);
binding.edtTitle.setFocusableInTouchMode(true);
binding.edtTitle.setOnTouchListener(this);
binding.edtTitle.setOnClickListener(this);
}
===============EDIT===============
Add in edittext
android:duplicateParentState="true"
If this not works then try with this line also
android:duplicateParentState="true"
android:clickable="false"
Here is a work around.
// Inside HeadingEditText.kt
binding.edtTitle.setOnClickListener {
this#HeadingEditText.performClick()
}
Set the OnClickListener at your Activity
edt_country.edtTitle.setOnClickListener {
// foo action
}
THIS IS NOT A GOOD SOLUTION
JUST USABLE IN A CUSTOM-VIEW USING A FrameLayout
on your parent (ViewGroup) of contained EditText, override onInterceptTouchEvent method like this:
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return true
}
I use EditText inside a FrameLayout and override the method inside my FrameLayout and all of them used inside a recycler list item (xml)... and Worked fine click listener of recycler root item view...

How to bind method on RadioGroup on checkChanged event with data-binding

I was searching over the internet for how to perform the new cool android data-binding over the RadioGroup and I didn't find a single blog post about it.
Its a simple scenario, based on the radio button selected, I want to attach a callback event using android data binding. I don't find any method on the xml part which allows me to define a callback.
Like here is my RadioGroup:
<RadioGroup
android:id="#+id/split_type_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:checkedButton="#+id/split_type_equal"
android:gravity="center"
<!-- which tag ? -->
android:orientation="horizontal">
...
</RadioGroup>
How do I attach a handler method which will be called on RadioGroup's checkChnged event will fire using data-binding?
I have tried using onClick (don't know if it is the same) in layout file and defining method in the Activity and located it using this in the layout file:
<variable
name="handler"
type="com.example.MainActivity"/>
...
<RadioGroup
android:onClick="handler.onCustomCheckChanged"
.. >
And defined method onCustomCheckChanged like this:
public void onCustomCheckChanged(RadioGroup radio, int id) {
// ...
}
But, it gives me the compilation error:
Error:(58, 36) Listener class android.view.View.OnClickListener with method onClick did not match signature of any method handler.onCustomCheckChanged
I have seen many blogs mentioning it is possible with RadioGroup but non of them really say how. How can I handle this with data-binding ?
After digging to the bunch of methods, I found this question on SO which helped me understand how to bind single methods of listeners.
Here is what to do with RadioGroup:
In RadioGroup listener you have a method onCheckedChanged(RadioGroup g, int id). So you can directly bound that method to your handler or your activity by passing an instance of it as a variable in layout file and calling a method with the same signature.
So call on layout file like this:
<RadioGroup
android:id="#+id/split_type_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:checkedButton="#+id/split_type_equal"
android:gravity="center"
android:onCheckedChanged="#{handler.onSplitTypeChanged}"
android:orientation="horizontal">
...
</RadioGroup>
And in my activity or handler, I need to simply provide the method with same name and signature like this:
public void onSplitTypeChanged(RadioGroup radioGroup,int id) {
// ...
}
Just make sure method is public.
NOTE: This works for any (most of, I have not tried all) listener methods. Like for EditText you can provide android:onTextChanged and so on.
I am using a string, and in this case I have bindable based on viewModel.getCommuteType() viewModel.setCommuteType(String)
<RadioGroup
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.DRIVING)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.DRIVING)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="D"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.BICYCLE)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.BICYCLE)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.WALKING)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.WALKING)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="W"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.BUS)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.BUS)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="T"/>
After some hours I found easy way: two-way databinding in android. It's base skeleton with livedata and Kotlin. Also you can use ObservableField()
Set your viewmodel to data
Create your radiogroup with buttons as you like. Important: set all radio buttons id !!!
Set in your radio group two-way binding to checked variable (use viewmodel variable)
Enjoy)
layout.xml
<data>
<variable
name="VM"
type="...YourViewModel" />
</data>
<LinearLayout
android:id="#+id/settings_block_env"
...
>
<RadioGroup
android:id="#+id/env_radioGroup"
android:checkedButton="#={VM.radio_checked}">
<RadioButton
android:id="#+id/your_id1"/>
<RadioButton
android:id="#+id/your_id2" />
<RadioButton
android:id="#+id/your_id3"/>
<RadioButton
android:id="#+id/your_id4"/>
</RadioGroup>
</LinearLayout>
class YourViewModel(): ViewModel {
var radio_checked = MutableLiveData<Int>()
init{
radio_checked.postValue(R.id.your_id1)//def value
}
//other code
}
Often you care more about what was actually checked instead of "something was checked". In such case alternative solution is to ignore RadioGroup and bind all items as below:
<RadioGroup (...) >
<RadioButton (...)
android:checked="#={viewModel.optionA}"/>
<RadioButton (...)
android:checked="#={viewModel.optionB}"/>
<RadioButton (...)
android:checked="#={viewModel.optionC}"/>
</RadioGroup>
where optionA, optionB and optionC are defined in ViewModel like below:
public final ObservableBoolean optionA = new ObservableBoolean();
public final ObservableBoolean optionB = new ObservableBoolean();
public final ObservableBoolean optionC = new ObservableBoolean();
This is usually enough, however if you want to react immediately on click then you can add callBacks and use them like that:
OnPropertyChangedCallback userChoosedA = new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(Observable sender, int propertyId) {
(...) // basically propertyId can be ignored in such case
}
};
optionA.addOnPropertyChangedCallback(userChoosedA);
Advantage of such approach is that you don't need to compare and track "id".
In my current project, I did it like this.
I have three currency in the project and I choose one of them via RadioGroup.
It's enum with currencies:
enum class Currency(val value: Byte) {
USD(0),
EUR(1),
RUB(2);
companion object Create {
fun from(sourceValue: Byte): Currency = values().first { it.value == sourceValue }
fun from(sourceValue: String): Currency = values().first { it.toString() == sourceValue }
}
}
A piece of my ViewModel:
class BaseCurrencyViewModel : ViewModelBase<BaseCurrencyModelInterface>() {
/**
* Selected currency
*/
val currency: MutableLiveData<Currency> = MutableLiveData()
/**
*
*/
init {
currency.value = Currency.USD // Init value
}
}
Part of my layout (pay attention to binding in RadioGroup and tags of RadioButton):
<RadioGroup
android:id="#+id/currencySwitchers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:selectedCurrency = "#{viewModel.currency}"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintEnd_toEndOf="parent">
<RadioButton
android:id="#+id/usdSwitcher"
android:text="USD"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="USD"
/>
<RadioButton
android:id="#+id/eurSwitcher"
android:text="EUR"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="EUR"
/>
<RadioButton
android:id="#+id/rubSwitcher"
android:text="RUB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="RUB"
/>
</RadioGroup>
And the final part - binding adapter.
#BindingAdapter("selectedCurrency")
fun setSelectedCurrency(view: View, value: MutableLiveData<Currency>?) {
view.getParentActivity()?.let { parentActivity ->
value?.observe(parentActivity, Observer { value ->
view.findViewWithTag<RadioButton>(value.toString())
?.also {
if(!it.isChecked) {
it.isChecked = true
}
}
}
)
(view as RadioGroup).setOnCheckedChangeListener { radioGroup, checkedId ->
val currency = Currency.from(radioGroup.findViewById<RadioButton>(checkedId).tag as String)
if(value != null && value.value != currency) {
value.value = currency
}
}
}
}
In this way, I got two-way binding between RadioGroup and a property in my ViewModel.

dynamic number of gui elements in Android?

I want to create a gui application for android where the user will be able to add or remove fields of certain type (4 different type of fields) to the application. Is there a way to do so in xml?
The only way I could figure to do so is by edditing the xml file from within the app which sounds as a bad idea for me.
Hope my question is clear.
Yotam.
Edit:
I have added a simple code for direct java implantation:
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.TextView;
public class Leonidas extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.counter);
TextView TV = new TextView (this);
TextView UV = new TextView (this);
TV.setText("hello");
UV.setText("goof");
//setContentView(TV);
//setContentView(UV);
ViewGroup.LayoutParams lpars = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
this.addContentView(UV,lpars);
this.addContentView(TV, lpars);
this.setVisible(true);
}
}
Edit2:
I have searched for example and got the following working:
LayoutInflater inflater;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
inflater = LayoutInflater.from(this);
Button b = (Button) this.findViewById(R.id.alert);
b.setOnClickListener(this);
}
#Override
public void onClick(View v) {
final LinearLayout canvas = (LinearLayout)Leonidas.this.findViewById(R.id.counter_field);
final View cv = this.inflater.inflate(R.layout.counter,canvas,false);
canvas.addView(cv);
}
You can do it from within your handler too (in the implementation class).
After inflating your xml layout, you respond to some kind of user interactions.
In the handler you
either create a new View from
scratch, and specify its
layoutparams,
or inflate one using xml
After having the new view, you add it to the current (this) view, and due to its layoutparams, it will be the size, shape, color, etc. that you want.
Update:
If you'd like to add more complex views to your activity, it's better to write them in xml, and inflate them:
sample_component.xml: //inside res/layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:padding="0px">
<TextView android:id="#+id/servicename_status" android:paddingLeft="15px"
android:paddingRight="5px"
android:textStyle="bold" android:focusable="false" android:textSize="14px"
android:layout_marginLeft="10px" android:layout_marginRight="3px"
android:layout_width="fill_parent" android:layout_height="wrap_content" />
<TextView android:id="#+id/lastcheck" android:focusable="false"
android:textSize="14px" android:layout_width="fill_parent"
android:layout_marginLeft="10px" android:layout_marginRight="3px"
android:layout_height="wrap_content" android:layout_below="#id/servicename_status" />
<TextView android:id="#+id/duration" android:focusable="false"
android:textSize="14px" android:layout_width="fill_parent"
android:layout_marginLeft="10px" android:layout_marginRight="3px"
android:layout_height="wrap_content" android:layout_below="#id/lastcheck" />
<TextView android:id="#+id/attempt" android:focusable="false"
android:textSize="14px" android:layout_width="fill_parent"
android:layout_marginLeft="10px" android:layout_marginRight="3px"
android:layout_height="wrap_content" android:layout_below="#id/duration" />
<TextView android:id="#+id/statusinfo" android:focusable="false"
android:textSize="14px" android:layout_width="fill_parent"
android:layout_marginLeft="10px" android:layout_marginRight="3px"
android:layout_height="wrap_content" android:layout_below="#id/attempt" />
<CheckBox android:id="#+id/alert" android:focusable="false"
android:layout_alignParentRight="true" android:freezesText="false"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="5px" />
</RelativeLayout>
Inside your Leonidas activity class you have the handlers that have to respond to different user actions by adding/removing items to/from the view.
Below is a sample handler of a click event, which uses LayoutInflater, to add the sample_component.xml view to your activity:
public final class MyClickListener implements View.OnClickListener
{
private LayoutInflater inflater;
public MyClickListener()
{
inflater = LayoutInflater.from(Leonidas .this);
}
#Override
public void onClick(View v)
{
// TODO: change RelativeLayout here to whatever layout
// you'd like to add the new components to
final RelativeLayout canvas = (RelativeLayout)Leonidas.this.findViewById(R.id.my_canvas);
final View childView = inflater.inflate(R.layout.sample_component, canvas, false);
// TODO: Look up the 5 different signatures of the addView method,
// and pick that best fits your needs
canvas.addView(childView);
// check which button was pressed
switch (view.getId())
{
case R.id.btn_prev:
//handler for the prev button
break;
case R.id.btn_next:
//handler for the next button
break;
default:
break;
}
}
}
Note, that MyClickListener is implemented as an inline class within your Leonidas activity, thay's why for the context parameter it is used: this.Leonidas.
Update
The R.id.my_canvas would be the id of the view that you want to add components to. it is in your main.xml (or whatever xml you use for your Leonidas view).
If you put the MyClickListener class inside your Leonidas.java class (declare as inline class), it will recognize it.
Instead of specifying elements in the XML, you can create them dynamically and add it to the UI. This is demonstrated in the Android Hello World Tutorial here.

Categories

Resources