custom view inside of a custom viewGroup not visible, how can I get it to show up?
or is there a better way to do this that would work?
no compile or runtime errors but the view does not show up in the viewGroup, it is supposed to fill the area with color like the other views but it is white and the color for the view is not showing up inside of the CustomLayout
xml code, the first 2 views show up with no problems but the 3rd view that is nested inside of the CustomLayout does not show up, just white color area, the view inside not visible
CustomViewOne is a separate class file, CustomViewTwo and CustomViewThree are both nested inside the MainActivity class as static inner classes, and CustomLayout is a separate file
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity" >
<com.example.customviewexample.CustomViewOne
android:layout_width="100dp"
android:layout_height="50dp" />
<view
class="com.example.customviewexample.MainActivity$CustomViewTwo"
android:layout_width="100dp"
android:layout_height="50dp" />
<com.example.customviewexample.CustomLayout
android:layout_width="100dp"
android:layout_height="50dp">
<view
class="com.example.customviewexample.MainActivity$CustomViewThree"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.example.customviewexample.CustomLayout>
</LinearLayout>
here is the code for the CustomViewThree, vary simple like the other custom Views it just fills the area with color, it is nested inside of the MainActivity so you have to use MainActivity$CustomViewThree to access it.
public static class CustomViewThree extends View {
public CustomViewThree(Context context) {
super(context);
}
public CustomViewThree(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomViewThree(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
}
}
and here is the code for the CustomLayout class
public class CustomLayout extends FrameLayout {
public CustomLayout(Context context) {
super(context);
init(context);
}
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CustomLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public void init(Context context) {
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
}
custom view inside of a custom viewGroup not visible, how can I get it
to show up?
Your parent CustomLayout which wraps the child has a empty onLayout() method which makes the child to not appear. This method is important in a ViewGroup because it's used by the widget to place its children in it. So, you need to provide an implementation for this method to place the children(by calling the layout() method on each of them with the proper positions). As CustomLayout extends FrameLayout you could just call the super method to use FrameLayout's implementation or even better remove the overridden method(is there a reason for implementing it?).
Related
I need to create my own ImageView.
This is my class:
public class Brick extends ImageView implements Serializable{
public Brick(Context context) {
super(context);
}
public Brick(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Brick(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}
When I try to use my ImageView inside a xml layout file (as you can see below) I have a problem. I can see a black shape, but there is not the image (the drawable called d) inside it.
<com.myapp.Brick
android:id="#+id/myBrick"
app:srcCompat="#drawable/d"
android:background="#000000"
android:layout_width="300dp"
android:layout_height="300dp" />
What's my error?
You should call android:src="#drawable in your XML Section .
<com.myapp.Brick
android:id="#+id/myBrick"
app:srcCompat="#drawable/d"
android:background="#000000" // showing Black Shape Background
android:layout_width="300dp"
android:layout_height="300dp"
android:src="#drawable/add_image /> // Add android:src
You should add app:srcCompat or android:src in your XML Section
I have a hierarchy of custom views that looks like this:
Activity(RelativeLayout) -> ParentLayout(FrameLayout) -> ChildLayout(LinearLayout)
The activity and parent layout are added and displayed just fine, but the child is not. I have looked at the hierarchy viewer in the device monitor to confirm it is not being added to the view hierarchy.
Really all I'm trying to do here is create a view hierarchy so I can play around with handling touch events at various places in the view.
Here is everything:
main_activity.xml
<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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<net.openeye.touchevents.ParentLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#558833" />
</RelativeLayout>
parent_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<net.openeye.touchevents.ParentLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.openeye.touchevents.ChildLayout
android:id="#+id/child_view"
android:layout_width="300dp"
android:layout_height="300dp" />
</net.openeye.touchevents.ParentLayout>
ParentLayout.java:
public class ParentLayout extends FrameLayout implements View.OnTouchListener {
public ParentLayout(Context context) {
super(context);
}
public ParentLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ParentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
child_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<net.openeye.touchevents.ChildLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#0066dd"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hi"/>
</net.openeye.touchevents.ChildLayout>
ChildLayout.java:
public class ChildLayout extends LinearLayout {
public ChildLayout(Context context) {
super(context);
}
public ChildLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ChildLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
What am I missing? I have another project that is basically set up the same way, except the child views are dynamically inflated and added, instead of being directly added in the xml layout files. This seems like it should work and I don't understand why it doesn't.
So it looks like when you have a custom view class, you don't want to have the view of the layout file be the same type as the custom class. i.e., if I have ParentLayout.java, I don't want parent_layout.xml's root to be <net.openeye.TouchEvents.ParentLayout>. It seems that when you want both a custom layout file and custom view class, you need to have the view class inflate the layout. If the layout has an element (the root, on this case) that is the same as the class, it will cause infinite recursion as the view inflates the layout, which instantiates the class, which inflates the layout... and so on.
I got this to work finally by making the following changes:
parent_layout.xml:
Change the root element from net.openeye.TouchEvents.ParentLayout to the class it extends, FrameLayout. It now looks like this:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- ... -->
</FrameLayout>
child_layout.xml:
Change the root element from net.openeye.TouchEvents.ChildLayout to the class it extends, LinearLayout. It now looks like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="300dp"
android:orientation="vertical">
<!-- ... -->
</LinearLayout>
ParentLayout.java: Inflate it's layout during instantiation. It now looks like this:
public ParentLayout(Context context) {
super(context);
init(context);
}
public ParentLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ParentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
inflate(context, R.layout.parent_layout, this);
}
ChildLayout.java: Same thing as ParentLayout.java, but inflate child_layout.
After getting this working and thinking about why this is happening, it makes sense that this is how it works.
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 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();}