Android: clipChildren=false and onClickListner for clipped children - android

I have a problem.
We have layout custom frame layout with scaling and translating functionality
public class MyFrameLayout extends FrameLayout {
...
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
getChildAt(0).setTranslationX(vTranslate.x);
getChildAt(0).setTranslationY(vTranslate.y);
getChildAt(0).setScaleX(mScale.scaleFactor);
getChildAt(0).setScaleY(mScale.scaleFactor);
}
The class listens for touch gestures and translations/scale its child.
I use it as parent viewgroup for my ViewGroup with content.
<MyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/gray"
android:clipChildren="false">
<android.support.constraint.ConstraintLayout
android:id="#+id/calc_constraint_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false"/>
Content for constraint layout adds programmaticaly and it is bigger then screen or parent group. Because of it we set clipChildren=false.
But the children which was out of bounds before transation don't response on onClick events.
Some pictures:
Start screen
After translation:
The 6% node just doesn't answer to clicks.
Please, help me.
Add:

Well. I couldn't find the way to make constraint layout(white one) to fit the content with wrap_content value. My workaround was to dynamicaly increase width and height of the constraint layout accordingly width and height of my node tree.
When you add additional node - layout measures grows and you see how it tweaks abit. Then to fix it i had to override onLayout() method in parent layout (It's green on the screenshots, but it was custom ZoomableLayout).
And now everything works fine. But i'm not sure if this implementation ugly or not.

Related

How to resize Layout height based on the position of child views

I have LinearLayout that has child views. The child views are stack one at the top of the other because the parent layout's orientation is vertical. All the children have their height and width wrap_content so they move freely anywhere within the parent layout. User can move the views and remove them as they wish. When the user removes a view, the parent layout height resizes. So far my code works well.
But when the user moves one view to the side of another view I would like the parent layout to resize it's height the same way as if the user removed the view. I tried to get the height of the parent and subtract the distance the child moved and redraw the layout but that didn't work. I also tried other ways but I have not been successful yet. Can someone help me?
You can use GridView for your case, where you can set the number of columns (android:numColumns) to 1, when vertically aligned and when moving to the side make it to 2.
Here is the documentation on how to use GridView https://developer.android.com/guide/topics/ui/layout/gridview.html
<GridView android:id="#+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
android:layout_margin="10dp"
android:horizontalSpacing="10dp"
android:numColumns="2"
android:verticalSpacing="10dp" />

Determine which view items are visible and most centered in a horizontal scrollview in android?

I have a custom horizontal scrollview defined as in xml:
<com.myapp.views.MyHorizontalScrollView
android:id="#+id/myScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="#+id/myLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
</LinearLayout>
</com.myapp.views.MyHorizontalScrollView>
I am dynamically inflating and adding child view to the linear layout (as above). This works nicely so far.
Also, I have extended the Horizontal scrollview. This is to add an onscroll listener which gives me onscroll event, and seems to be working
Question
When the user scrolls across on the scrollview, I need to determine if any of the views are now visible to the user i.e. shown on screen.
Also, I would like to determine the most centered view in scrollview (again that is visible to the user)
is this possible?
to determine if a View is visible you can do this like Bill Mote
Rect scrollBounds = new Rect();
scrollView.getHitRect(scrollBounds);
if (imageView.getLocalVisibleRect(scrollBounds)) {
// Any portion of the imageView, even a single pixel, is within the visible window
} else {
// NONE of the imageView is within the visible window
}
is stated as answer to this question Android: how to check if a View inside of ScrollView is visible?
there you can play to see which one is more centered with a little math and the order in which you added your views

Android - Layout that fills the screen (using weight) and scrollable when soft keyboard is out

I need to build a layout that fills the screen. I do that using a LinearLayout with weights in their child views.
This layout is a form, so I also need it to be scrollable when the soft keyboard is out.
What happens is that the screen height is shrunk when the keyboard is out, so the views are shrunk too, crowded together. They look awful.
Do you know any way to build a form layout that fills the screen but at the same time preserves its aspect and can be scrollable when the soft keyboard is out? This is really easy in iOS but in Android... I can't think of a solution.
Thank you
iOS always has the same screensize, Android doesnt. You need to use a responsive design in Android since you dont know how big the screen is that the user is using.
I dont think you need weights(not verticle anyway) to fix this.
Just use a ScrollView and add a LinearLayout(orientation:vertical) inside it.
Add your views inside this LinearLayout, and if you need to have multiple views horizontally. Add another LinearLayout(orientation:horizontal)
Set margin on your views to get a nice distance between them.
This will allow users that have small screens to scroll in your layout, and if the user has the keyboard out they can scroll aswell.
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
The first two will lie beneath each other.
The next two will lie next to each other, apply weights here if you want them to be of different sizes
Define your form within scroll view and in manifest make the windowSoftInputMode, configChanges entries as shown below
<activity
android:name="com.example.MainActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
android:configChanges="keyboardHidden|orientation">
</activity>
Hopefully this can help you.
I have built the following scheduleConsolideHeights method to solve the problem. Thanks to Joakim for his comments.
Although it works fine for me, I'm sure it can be improved. Any suggestion will be welcome.
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.XXX);
// LinearLayout from your R.layout.XXX that has vertical orientation and
// its children have weights instead of absolute heights
final LinearLayout layout = (LinearLayout) findViewById(R.id.layout_with_weights);
scheduleConsolideHeights(layout);
}
/**
* Adds a listener to the layout {#link ViewTreeObserver} to wait for the view measurements
* and then calls {#link #consolideHeights(LinearLayout)}.
*/
private static void scheduleConsolideHeights(final LinearLayout layout) {
final ViewTreeObserver viewTreeObserver = layout.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
consolideHeights(layout);
}
});
}
}
/**
* Note: you might want to use {#link #scheduleConsolideHeights(android.widget.LinearLayout)}.
*
* Takes a {#link android.widget.LinearLayout} and, for each of its child views, sets the height
* of the child's LayoutParams to the current height of the child.
*
* Useful when a {#link android.widget.LinearLayout} that has relative heights (with weights)
* may display the keyboard. With absolute heights, the layout maintains its aspect when the soft
* keyboard appears.
*
* See: http://stackoverflow.com/q/22534107/1121497
*/
private static void consolideHeights(LinearLayout layout) {
for (int i = 0; i < layout.getChildCount(); i++)
{
final View child = layout.getChildAt(i);
final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) child.getLayoutParams();
params.height = child.getHeight();
params.weight = 0;
child.setLayoutParams(params);
}
}
}
As SiGangteng response in that question that must help you to solve the problem (inside the specific in the manifest)
android:windowSoftInputMode="adjustPan"

How can I make a child view wider than it's parent view without setting an absolute width?

I'm trying to create a marquee style animated view wherein a very wide linear layout scrolls horizontally within a narrower view. Something like
<LinearLayout
android:id="#+id/ContentLinearLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:clipChildren="false">
<LinearLayout ...> <- a very wide layout that animates.
</LinearLayout>
Problem is I can't figure out how to make the view with the content in it not clip it's width to the size of it's parent without setting an exact layout_width. The animated content view is dynamically created so I don't know the width ahead of time. This is for an appwidget so I'm further constrained by the limitations of RemoteViews.
With RemoteViews you will have to specify a fixed width.

android: how to make a child view overlap the parent?

I need to implement the layout as in the picture. Parent and Sibling are in a vertical LinearLayout. So I need to make a child view to overlap it's parent. Can I do that in android?
If:
sibling is a sibling of parent
parent is a ViewGroup
and you really want child to be a child of parent
then maybe you could consider using android:clipChildren set to false on parent.
I was actually just looking at an example of a FrameLayout that had a TextView overlaid on top of an ImageView. So, there are obviously multiple ways to get it done. Your next question might be which one is best ... to that I have no idea, but here's a guy that might:
http://www.curious-creature.org/2009/03/01/android-layout-tricks-3-optimize-part-1/
Just contain them all within a RelativeLayout, and remember the draw order is top to bottom, so put the top most view on the bottom of the XML definition.
If you use a RelativeLayout you should have no problem achieving this effect. By default it will stack all of its children on top of each other in the top left corner if you don't supply them with android:layout parameters. So it will definitely support overlapping children. You'd just have to figure out what the best way to tell it where the child should go on the screen relative to something else.
There are at least two layouts that can do that. AbsoluteLayout and RelativeLayout. I suggest that you put your views in a RelativeLayout and add them with LayoutParams that specify their offset form the top and left of the parent:
RelativeLayout.LayoutParams rlp;
label = new TextView(ctx);
label.setBackgroundColor(0x00000000);
label.setTextColor(0xFF7ea6cf);
label.setTextSize(13);
label.setGravity(Gravity.LEFT);
label.setText("Examples:\n- Fentanyl\n- Dilaudid 2 mg PO q 4 hours prn moderate pain");
rlp = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT,100);
rlp.topMargin=189;
rlp.leftMargin=30;
rlp.rightMargin=30;
rlParent.addView(label,rlp);
In my case, I have to set android:clipCildren to be false on the parent of parent.
i.e.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:id="#+id/parent1">
<FrameLayout
android:id="#+id/parent2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="64dp"
android:background="#android:color/holo_blue_bright">
<View
android:id="#+id/This_is_the_view_I_want_to_overlap_parent2"
android:layout_width="160dp"
android:layout_height="80dp"
android:layout_gravity="top|start"
android:layout_marginTop="-40dp"
android:background="#000000" />
</FrameLayout>
</FrameLayout>

Categories

Resources