Detect if view is scrolled out of the screen - android

I have layout with scrollView as below :
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/transparentLayout"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="#android:color/transparent"
android:orientation="vertical" >
</LinearLayout>
... other views
</ScrollView>
I want to detect if the transparentLayout (LinearLayout) is scrolled out of the screen.

I solved it in this fashion:
scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
#Override
public void onScrollChanged() {
Rect scrollBounds = new Rect();
scrollView.getHitRect(scrollBounds);
if (layout.getLocalVisibleRect(scrollBounds)) {
// if layout even a single pixel, is within the visible area do something
} else {
// if layout goes out or scrolled out of the visible area do something
}
}
});

Related

Flickers while layout visible/gone

Is there any way to hide a view without flickering its above view?
I am trying to hide a View below MapView. Once I set its visibility to GONE, MapView flickers. As I have to add more markers dynamically, couldn't able to keep MapView and bottomView in FrameLayout, since the bottomView will hide those markers in small size screens.
Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<com.myapp.widgets.MapPlacePicker
android:id="#+id/lay_fr_map_inc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/options_layout" />
<LinearLayout
android:id="#+id/options_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:animateLayoutChanges="true"
android:background="#FFFFFF"
android:orientation="vertical"
android:visibility="visible">
<com.myapp.widgets.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="Please select a location!!"
android:textAppearance="#android:style/TextAppearance.Small" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.aigestudio.wheelpicker.WheelPicker
android:id="#+id/main_option_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_weight="0.5"
app:wheel_atmospheric="true"
app:wheel_curved="false"
app:wheel_item_space="15dp"
app:wheel_item_text_color="#ffafafaf"
app:wheel_item_text_size="12dp"
app:wheel_selected_item_text_color="#color/colorPrimary"
app:wheel_visible_item_count="3" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Output:
I have also tried TranslationAnimation, but no luck. Its showing more gray space than before.
int fromY = (visibility == View.GONE) ? 0 : optionLayout.getHeight();
int toY = (visibility == View.GONE) ? optionLayout.getHeight() : 0;
if (visibility == View.VISIBLE) {
optionLayout.setVisibility(visibility);
}
TranslateAnimation animate = new TranslateAnimation(
0, // fromXDelta
0, // toXDelta
fromY, // fromYDelta
toY); // toYDelta
animate.setDuration(1000);
animate.setInterpolator(new AccelerateDecelerateInterpolator());
//animate.setFillAfter(false);
animate.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (visibility == View.GONE)
optionLayout.setVisibility(visibility);
optionLayout.clearAnimation();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
optionLayout.startAnimation(animate);
I don't see any flickering in that animation; if you want to avoid the vertical resizing behavior of lay_fr_map_inc then you can just remove this attribute:
android:layout_above="#+id/options_layout"
...and maybe make the height match_parent. Then, lay_fr_map_inc will stay full height, but the bottom portion will be hidden by options_layout when it appears (instead of scooting upwards).
Don't forget to change the map padding when you do this, so you don't obscure the Google logo (which is a violation of the rules): setPadding()

ImageView AlignParentBottom

In my application I have an ImageView that gets with buttom alignment, in a RelativeLayout which is the root view of the Layout:
The problem is that when the keyboard is opened, it goes up together:
I tried to fix it by putting it in Manifest: `android:windowSoftInputMode="stateVisible|adjustPan",
It works, the problem is that the FloatingButton stops scrolling too, is there any way to make ImageView only "locked" down when the keyboard opens?
The xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:layout_alignParentBottom="true"
app:srcCompat="#drawable/ic_rodape"/>
<ScrollView........../>
<android.support.design.widget.FloatingActionButton
android:id="#+id/ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_margin="8dp"
app:backgroundTint="#color/colorPrimary"
app:srcCompat="#drawable/back"/>
</RelativeLayout>
Instead of using android:windowSoftInputMode="stateVisible|adjustPan" use this to hide specific views RelativeLayout rootView = (RelativeLayout) findViewById(R.id.root)
rootView is just a view pointing to your root view in this case a relative layout(give an id to your Relative layout)
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
int heightDiff = rootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
//when the keyboard is up...
view_one.setVisibility(View.GONE);
}else{
//when the keyboard is down...
view_one.setVisibility(View.VISIBLE);
}
}
});
Thanks to answers here and here

View.getTop() always returns 0

So View.getTop() is, as per the docs:
Top position of this view relative to its parent.
I have the following layout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/root"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.scrollviewtest1.MainActivity">
<LinearLayout
android:id="#+id/scroll_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.scrollviewtest1.MyTextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/large_text" />
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
</ScrollView>
I am checking for getTop() for LinearLayout as I scroll up and down and getTop() always returns 0. Shouldn't it change as it moves up and down relative to its parent?.
How I checked it?
I stored reference to the LinearLayout inside the child TextView and called invalidate() every time there was scrolling:
ScrollView root = ((ScrollView) findViewById(R.id.root));
root.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
textView.invalidate();
}
});
and checked inside the onDraw() call of the child TextView
Try this way :
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
int top = view.getTop();
}
}, 300);// delay times in milliseconds
You can set delay time as per your requirement.
To get the LinearLayout scrolled position call myScrollView.getScrollY();
getTop(); returns what you entered as marginTop in your xml layout and it not varies when the thing is scrolled, to know the actual current position you need to take in account getScrollY(); too

Clicking a scroll view

I have a scroll view that has a Linearlayout child and this linearlayout has a drawingview.
the problem : I tried almost all the available answers on this topic and none of them worked, I cant understand why click is not fired for (scrollview, linear layout and even drawingview).
note : I tried setting on click for each of the three and none worked.
the xml code:
<ScrollView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#id/scrollview"
android:clickable="true"
>
<LinearLayout
android:setorientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#id/linear"
android:clickable="false">
<Customview
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#id/draw"
android:clickable="false"/>
</LinearLayout>
</ScrollView>
First your ScrollView ,layout_height is wrapped! and for children you gave match_parent i doubt your view won't even display. Isn't it?
Then no idea why you use setorientation and android:id="#id/draw" instead of android:orientation and android:id="#+id
If you want to check scrolling works use
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
Log.d("TAG", "onScrollChanged: ");
// DO SOMETHING WITH THE SCROLL COORDINATES
}
});
You are using unnecessary attributes check this example :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#8768"
android:orientation="vertical">
<ScrollView
android:id="#+id/scrollIndicatorDown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#823">
<LinearLayout
android:id="#+id/first_child"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#900"
android:orientation="vertical">
<LinearLayout
android:id="#+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#000"
android:orientation="vertical"></LinearLayout>
<LinearLayout
android:id="#+id/web_view"
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="#987"
android:orientation="vertical"></LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
If you write an onClickListner to the id linear_layout it just work normally!
Answer :The child Views of your ScrollView are consuming the click events you do on the ScrollView.
The solution to this problem is to set the onClickLIstener to the immediate child of the ScrollView(It's child).
So according to my example if i want to find out the ScrollView onClick i write my listener to its child.
scrolChild =(LinearLayout) findViewById(R.id.first_child) ;
scrolChild .setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(YourActivityName.this, "You Clicked Me OH yeaaaaa", Toast.LENGTH_SHORT).show();
}
});
Read here when you need androidclickable-true android:clickable="true" mean's that it's not clickable?
This is my activity
public class MainActivity extends AppCompatActivity {
private ScrollView scrollView;
private LinearLayout scroolChild;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web);
scrollView = (ScrollView) findViewById(R.id.scrollIndicatorDown);
scroolChild =(LinearLayout) findViewById(R.id.first_child) ;
scroolChild.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "You Clicked Me OH yeaaaaa", Toast.LENGTH_SHORT).show();
}
});
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
Log.d("TAG", "GotAScrollChanged: ");
// DO SOMETHING WITH THE SCROLL COORDINATES
}
});
}
}
You have set android:clickable="false" for both make it true it will work for you
<ScrollView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#id/scrollview"
android:clickable="true"
>
<LinearLayout
android:setorientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#id/linear"
android:clickable="true">
<Customview
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#id/draw"
android:clickable="true"/>
</LinearLayout>
</ScrollView>

Android: RelativeLayout translateY animation with layout_alignParentBottom

I'm working on an Android app with an animation where a vertically central view should be animated from the center to the top of the screen. Below this view is another view containing related content, which is aligned directly below the center view. When the center view animates up, I want the lower view to be 'pinned' to the top but also to the bottom of the screen (as per layout_alignParentBottom="true"). Currently though, as the bottom view animates up a gap is left between the bottom view and the bottom of the screen:
What's the easiest way to animate the bottom view, while keeping it pinned to the bottom of the screen?
Here is my layout XML:
<?xml version="1.0" encoding="utf-8"?>
<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="newsoni.com.testrelativelayouttranslation.MainActivity">
<View
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#FF0000"
android:layout_centerVertical="true"
android:id="#+id/centerBar" />
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#00FF00"
android:layout_below="#+id/centerBar"
android:id="#+id/bottomPanel" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Do animation"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:id="#+id/btn" />
</RelativeLayout>
Here is my Java:
public class MainActivity extends AppCompatActivity {
private View mCenter, mBottomPanel;
private Button mBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCenter = findViewById(R.id.centerBar);
mBottomPanel = findViewById(R.id.bottomPanel);
mBtn = $(R.id.btn);
mBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int value = mCenter.getTranslationY() == 0 ? -mCenter.getTop() : 0;
mCenter.animate()
.translationY(value)
.setDuration(250)
.start();
mBottomPanel.animate()
.translationY(value)
.setDuration(250)
.start();
}
});
}
#SuppressWarnings("unchecked")
public <T extends View> T $(int id) {
return (T) findViewById(id);
}
}
Here is a link to the project which you can download:
https://drive.google.com/file/d/0B-mqMIMqm_XHamxENkhIZDJDMHM/view?usp=sharing
I ended up using a standard Animation and overriding applyTransformation to manually alter the LayoutParams of the bottom view.

Categories

Resources