As the title, i want to know if there is a the best way to control a view that added dynamically. (we have to keep reference to the view that was added)
Some time, for a complex request we have to add view in runtime. The is some ways to do that. In my case:
Some time i use a listview/recyclerview and control view via the list/recycleview adapter.
Other way is use a hashmap.
Do you have any other ideas? and how it work?
I prefer way, when I define View both by Java and XML file. View created like this, gives you ability to call your own Java methods, but you don`t need to create whole layout dynamically in Java. Little example:
MyView.java:
public class MyView extends LinearLayout {
TextView textView;
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init() {
inflate(getContext(), R.layout.my_view, this);
setOrientation(VERTICAL);
textView = (TextView) findViewById(R.id.text_view);
}
public MyView setContent(String value) {
textView.setText(value);
return this;
}
}
my_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
After that, you can simply add it in you layout through Java:
cont.addView(new MyView(this).setContent("Value"));
or xml:
<com.path.to.your.view.MyView
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
I am trying to extend a cardview to set the background image. I know that this can not be done with normal cardview. I have searched net and found plenty of solutions for setting a background color to the card view but none for image.
My code to do so:
public class CCView extends CardView {
public CCView (Context context) {
super(context);
init();
}
public CCView (Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CCView (Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setBackground(getResources().getDrawable(R.drawable.cc_background));
}
}
I get this exception when I populate the code from XML
android.graphics.drawable.BitmapDrawable cannot be cast to android.support.v7.widget.RoundRectDrawableWithShadow
Any solution?
As CardView extends FrameLayout you can layer layouts on top of it. To get around the problem you're having, I'd try adding a blank view "underneath" all the other elements in your view, and then set that view to inherit the state of its parent. Something like this:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
card_view:cardBackgroundColor="#DDFFFFFF"
card_view:cardElevation="#dimen/card_elevation">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:duplicateParentState="true"
android:background="#drawable/card_background"/>
<LinearLayout
....
....
....
/LinearLayout>
</android.support.v7.widget.CardView>
I am learning to create a compound control in android.
For starters i tried an edit text with an attached button to clear it.
The problem is even though i can see the compound control in the graphical view of the
main.xml, there is an error message : "Custom view ClearableEditText is not using the 2- or 3-argument View constructors; XML attributes will not work"
This is not visible in project explorer under errors only in the xml graphical view
i am able to compile and run but get a force close.
XML : COMPOUND CONTROL clearable_edit_text.xml
<?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"
>
<EditText android:id="#+id/editText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button android:id="#+id/clearButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CLEAR"
/>
</LinearLayout>
CLASS
public class ClearableEditText extends LinearLayout
{
EditText et;
Button btn;
public ClearableEditText(Context context)
{
super(context);
LayoutInflater li=(LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
li.inflate(R.layout.clearable_edit_text,this,true);
et=(EditText)findViewById(R.id.editText);
btn=(Button)findViewById(R.id.clearButton);
hookupButton();
}
private void hookupButton()
{
btn.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
et.setText("");
}
});
}
}
main.xml
<?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"
>
<com.commsware.android.merge.ClearableEditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<com.commsware.android.merge.ClearableEditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
Your class extends LinearLayout but you never add any views to it. You need to call addView(...) and pass your inflated view as the parameter.
Also, to define your view in XML you need to override the 2 and 3 argument constructors for a LinearLayout. Add this to your code:
public ClearableEditText(Context context, AttributeSet attrs) {
super( context, attrs );
}
public ClearableEditText(Context context, AttributeSet attrs, int defStyle) {
super( context, attrs, defStyle );
}
To get all 3 constructors to use the same initialization code, move your code from the single argument constructor to the 3 argument constructor, then in the other 2 constructors call this(context, null, 0) and this(context, attrs, 0) respectively.
I have a simple input form; it's a vertical LinearLayout with EditTexts inside a ScrollView.
<ScrollView android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView style="#style/Text"
android:text="Name"/>
<EditText style="#style/EditBox"/>
</LinearLayout>
<View style="#style/Divider"/>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView style="#style/Text"
android:text="Password"/>
<EditText style="#style/EditBox"/>
</LinearLayout>
...
</LinearLayout>
</ScrollView>
When the user scrolls the form, it automatically moves its focus to the visible EditText.
It is possible to disable such behavior and always keep focus on the EditText currently selected by touch?
I understand that this may be a feature, but I need to disable it.
Thanks!
Just thought I'd share my solution to this. Even though some of the other answer's comments state that you cannot override this behavior, that is not true. This behavior stops as soon as you override the onRequestFocusInDescendants() method. So simply create your ScrollView extension to do this:
public class NonFocusingScrollView extends ScrollView {
public NonFocusingScrollView(Context context) {
super(context);
}
public NonFocusingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonFocusingScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
return true;
}
}
And you're done. The ScrollView will mess with your focus no more.
I have had such a problem too. The only way that helped me is to extend scroll view and to override neigher
#Override
public ArrayList<View> getFocusables(int direction) {
return new ArrayList<View>();
}
or
#Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
return true;
}
but to override ViewGroup.requestChildFocus(View child, View focused) method as following:
#Override
public void requestChildFocus(View child, View focused) {
// avoid scrolling to focused view
// super.requestChildFocus(child, focused);
}
What worked for me was combining #dmon's and #waj's answers.
Only overriding onRequestFocusInDescendants() worked great when I was only dealing with EditTexts inside of the ScrollView, but when I started added multiple View types, it didn't work so well.
Only overriding getFocusables() did not work at all.
Overriding both onRequestFocusInDescendants() AND getFocusables() seems to work beautifully in all scenarios.
public class FixedFocusScrollView extends ScrollView {
public FixedFocusScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public FixedFocusScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FixedFocusScrollView(Context context) {
super(context);
}
#Override
public ArrayList<View> getFocusables(int direction) {
return new ArrayList<View>();
}
#Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
return true;
}
}
I tried all solutions posted here but either didn't work on certain Android versions or it messed up with some other behavior like when switching between touch and non-touch mode (when you click buttons or use the trackpad).
I finally found that overriding the method getFocusables did the trick:
public class FixedFocusScrollView extends ScrollView {
public FixedFocusScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public FixedFocusScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FixedFocusScrollView(Context context) {
super(context);
}
#Override
public ArrayList<View> getFocusables(int direction) {
return new ArrayList<View>();
}
}
Try to cut the problem from the source (edit: i.e. move it to an XML file).
First, there must be a focusable element for that to happen. Make all focusable elements contained in that scroll into non-focusable elements. Make them focusable after the view is inflated and is visible.
android:focusable="false"
android:focusableInTouchMode="false"
I found another easy solution that works for my problem.
I got a ScrollView with an EditText at the top, and after it, a big list of TextViews, RatingBars and Buttons. The Buttons launch AlertDialogs, and when they pops up, the ScrollView moves to the top, to the EditText that is the one that still has the focus.
To solve it, I set in the onClick method of the Activity the requestFocusFromTouch() to the view clicked (in this case the Button).
public void onClick(View v) {
v.requestFocusFromTouch();
...
}
So now when I click on a Button, the ScrollView moves and put that Button on the center of the screen, that was just what I wanted.
I hope it help.
This method is very effective,you can overload computeScrollDeltaToGetChildRectOnScreen and return 0
public class NoScrollFocusScrollView extends ScrollView {
public NoScrollFocusScrollView(Context context) {
super(context);
}
public NoScrollFocusScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoScrollFocusScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
return 0;
}
}
For such behavior use nextFocusUp and nextFocusDown.
<EditText
android:id="#+id/my_edit_text"
android:nextFocusDown="#id/my_edit_text"
android:nextFocusUp="#id/my_edit_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</EditText>
Happened to me today, basically I was adding a View programmatically between some existing views, and Scroll automatically moved to focus that view. What I just did, is the following:
container.setFocusable( false );
This solved the issue for me. It may not be applicable in all situations, but works well for mine where the scrolling is done programmatically:
View originalFocus = getCurrentFocus();
scroller.fullScroll(View.FOCUS_DOWN);
if (originalFocus!=null) {originalFocus.requestFocusFromTouch();}
How can you implement a RadioButtonPreference in android? Just like the CheckBoxPreference.
Are there any workarounds?
Use a ListPreference. You need to have more than one radio button for it to be meaningful (otherwise, it would just be a checkbox).
If, for some reason, you do not want to use a ListPreference, grab the source code to CheckBoxPreference from the Android open source tree and roll your own Preference implementation. You should then be able to list your custom implementation in preference XML using the namespace (e.g., com.foo.RadioButtonPreference).
You can use a custom class extending from CheckBoxPreference like this:
public class RadioButtonPreference extends CheckBoxPreference {
public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
}
public RadioButtonPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
}
public RadioButtonPreference(Context context) {
this(context, null);
}
#Override
public void onClick() {
if (this.isChecked()) {
return;
}
super.onClick();
}
}
Then create a preference_widget_radiobutton.xml layout file:
<?xml version="1.0" encoding="utf-8"?>
<!-- Layout used by CheckBoxPreference for the checkbox style. This is inflated
inside android.R.layout.preference. -->
<RadioButton android:id="#+android:id/checkbox"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="false"
android:focusable="false"/>