Another Fragment on top op a Mapview (SupportMapFragment) - java

Im adding another Fragment to the screen. This screen already has en MapView in a SupportMapFragment so the added Fragment should be on top of the MapView. This new view cover like 2/3 of the screen and a big part of the Map but when I scroll on the View it scrolls the MapView underneath. This is not what i expected because the new View is added on top of the MapView. The new view exist of a relative layout containing a ImageView which wraps it contents. So when scrolling on the imageview (which has totally no functionality) it scrolls the MapView. Can anyone explain why this happens and if possible, provide me with a solution?
EDIT:
basically i have a MapView which fills the whole screen. This code sets up my mapview:
public void setUpMapIfNeeded(int satelliteMode, LatLng startPoint, float zoomLevel) {
// Do a null check to confirm that we have not already instantiated the map.
if (mapView == null) {
// Try to obtain the map from the SupportMapFragment.
mapView = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapview))
.getMap();
// Check if we were successful in obtaining the map.
if (mapView != null) {
setUpMap(satelliteMode, startPoint, zoomLevel);
}
}
}
private void setUpMap(int satelliteMode, LatLng startPoint, float zoomLevel) {
// more settings
}
Then when a user clicks a marker a fragment must be shown on top of the mapview.
public void createDetailView() {
detailView = new DetailViewFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.viewLayout, detailView).commit();
fragmentManager.executePendingTransactions();
}
This all works fine. The view is shown (which is about 2/3 of the whole screen) but user can scroll the map when swiping the detailview. The detailview consist of a relative layout with a lot of text and buttons:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_marginTop="45sp">
<!-- a lot of text and buttons here -->
</RelativeLayout>

So I still havent found a proper way to deal with this. Instead I just disabled all touches and clicks on the mapview when another view is on top of the mapview which btw works ok.

Just in case it might still be relevant, the way I've handled this kinds of layouts (one view appearing "on top of" another) is to use LinearLayout instead of a RelativeLayout in the following way:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<SomeView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<PopOutView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:visibility="gone" />
</LinearLayout>
In your case the map would be that SomeView and the relative layout the PopOutView. Then in the code you would just call popOutView.setVisibility = View.VISIBLE whenever you would like it to show up. It shrinks the first view instead of being drawn on top (thus having a bit different visual effect) but at least this way the touch events should go to the right view.

Set the fragment's layout clickable property to true. It will stop the touch events from propagating down.
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFF"
android:clickable="true">
</FrameLayout>

Related

The Button over SupportMapFragment inside a viewpager programmatically

I'm struggling with something really simple. ( or at least this was my idea.. )
I would need to put a simple button on top of a map inside a viewpager.
Actually I'm creating the supportmapfragment programmatically and adding it to the crated viewpager adapter .
ViewPagerAdapter adapter = new ViewPagerAdapter
(getSupportFragmentManager());
mapFrag = new SupportMapFragment();
mapFrag.getMapAsync(this);
adapter.addFragment(mapFrag, getString(R.string.maptab));
now... to put a button on top I would need the view from supportmapfragment so I can push up "my button_" via addview.
I cannot understand how to retrieve the view without extending the class for supportmapfragment but this would need me to create a custom supportmapfragment class.
any idea?
after suggestion: I made a test with a relative layout :
<fragment
android:id="#+id/rlMap"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</fragment>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Button 1"/>
this make button appear for a second (before map load) then being uncovered by map . even putting button inside the fragment sort same effect
Even if you try and put the button over the fragment's view, you will still need to set a click listener and do some logic when it's pressed. I think that would make the existing code a bit messy, passing a responsibility of the fragment (registering the button click listener) to the activity.
What I would do if I were you would be create a new Fragment with some ConstraintLayout that contains the underlying map and the button (but does not extend SupportMapFragment). It would be a wrapper fragment where you can also handle the button with its events, and whatever would be needed more.

how to set android ImageView visibility inside an included layout?

We are using android API 17 in our application. I have defined a layout containing two images vies as below:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/image_container_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/image_1_resource"/>
<ImageView
android:id="#+id/image_2"
android:layout_marginTop="3dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/image_container_layout"
android:src="#drawable/image_2_resource"/>
This layout is included inside another layout as below:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
style="#style/wizard_content_style"
tools:context=".ui.Wizard"
android:orientation="vertical"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
>
<include layout="#layout/image_container_layout"
android:id="#+id/included_view"
/>
<TextView
style="#style/wizard_content_text_style_medium"
android:id="#+id/text_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/included_view"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal"
android:text="#string/instruction"
android:layout_marginBottom="15dp"/>
The reason that the layout is included is that we want to reuse it in two more layouts.
Now based on some condition I want to hide or show the image views inside image_container_layout.
The java code looks like this:
containerLayout = (ViewGroup) ((Activity) getAndroidContext()).getLayoutInflater().inflate(R.layout.image_container_layout, null);
image1 = (ImageView) containerLayout.findViewById(R.id.image_1);
image2 = (ImageView) containerLayout.findViewById(R.id.image_2);
switch (accuracy) {
case 1:
log().i(getClass().getSimpleName(), "case 1 chosen");
image1.setVisibility(View.VISIBLE);
image2.setVisibility(View.GONE);
log().i(getClass().getSimpleName(), "image 1 has been shown");
break;
case 2:
image1.setVisibility(View.GONE);
image2.setVisibility(View.VISIBLE);
break;
case 3:
image1.setVisibility(View.VISIBLE);
image2.setVisibility(View.VISIBLE);
break;
}
I am debugging this code and I am sure the code is running. The log messages are printed in Logcat as well, but nothing happens no change in the images. Also, both images are always shown.
I wonder if there is something that I have to do when working with the included layout?
Thanks for any help in advance.
Based on answers I got below, seems that inflating a view will create a new object and because of this, changes in the visibility are not shown on the user interface.
Then the question is that if we have a wizard and inside 3 different pages of the wizard I want to have an image and depending on some condition I want to show or hide the image, what is the best solution? I mean I want to reuse the code which is responsible for hiding and showing the image regardless which page of wizard is active.
Why are you complexing with so much code. If you include some layout in your xml then you can use those widgets also same as the xml have. There is no need to inflate.
ImageView image_2 = findViewById(R.id.image_2);
image_2.setVisbility(Visible.GONE);
You said at this comment the code not inside activity but wherever it is you inflated a new layout to your view currently displaying by this line:
containerLayout = (ViewGroup) ((Activity) getAndroidContext()).getLayoutInflater().inflate(R.layout.image_container_layout, null);
When you try to change visibility of those images actually it works, i think so. But if your activity or fragment layout contains image_container_layout maybe you see
those images.
And I wonder that what do you do with inflated view containerLayout. Do you add it to inside of any other view. If you dont it wont be visible for you.
you have to use it like this:
View included_view1 = findViewById(R.id.included_view1);
ImageView image_1 = included_view1.findViewById(R.id.image_1);
ImageView image_2 = included_view1.findViewById(R.id.image_2);
image_1.setVisibility(View.VISIBLE);
image_1.setVisibility(View.GONE);
image_2.setVisibility(View.VISIBLE)
image_2.setVisibility(View.GONE)
View included_view2 = findViewById(R.id.included_view2);
ImageView image_11 = included_view2.findViewById(R.id.image_1);
ImageView image_22 = included_view2.findViewById(R.id.image_2);
image_11.setVisibility(View.VISIBLE);
image_11.setVisibility(View.GONE);
image_22.setVisibility(View.VISIBLE)
image_22.setVisibility(View.GONE)
Above code will be helpful in the case of multiple time you want to use same layout.

Weird OnItemClick Behavior (GridView in a Fragment)

I'm trying to 1) reveal a view and 2) modify another view in response to a user click on a view. The clickable view is populated by an adapter and set to a GridView. In my code, mTextView is a reference to another view in rootView. There are no NullPointer errors.
The strange problems are
In my code, for whatever method I call with LINE 3's mTextView, let it be setVisibility() or whatnot, LINE3 will draw (Shows changed text HELLO WORLD in at the other view), but LINE 1 just won't draw. The strange behavior is, with LINE 3, when I click the item the second time, LINE 1 works.
When I comment LINE 3 out, LINE 1 works on the first click. So, LINE 1's view is obviously not NULL (or could it?)
Yet another strange behavior is, LINE 2 always work as expected, the background color changed the first click, with or without LINE 3.
Each LINE1,LINE2 or LINE3 work perfectly on its own, in onItemClick.
What baffles me is why does LINE2 work but not LINE1, what are the possible dependencies between LINE3, LINE2, LINE1. Here is the code.
// Setup OnItemClickListener to respond to user click
mCardsGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// store the selected favor item as an instance, if it is not set already
mSelectedGameCardItem = (GameCardItem) parent.getItemAtPosition(position);
// Make the content visible (LINE 1)
view.findViewById(R.id.game_card_item_title).setVisibility(View.VISIBLE);
// Change the background color (LINE 2)
view.findViewById(R.id.game_card_item).setBackgroundColor(ContextCompat.getColor(getContext(), R.color.colorAccent));
// change tag line message at another view, rootView(LINE 3)
mTextView.setText(getResources().getString(R.string.favors_game_post_game_description, "HELLO WORLD"));
}
}
});
The XML of the item_card layout, this layout is used by the adapter to inflate the item in the grid.
<android.support.v7.widget.CardView
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="wrap_content"
android:layout_margin="8dp">
<LinearLayout
android:id="#+id/game_card_item"
android:padding="8dp"
android:background="#color/colorLightPrimary"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="16dp"
app:srcCompat="#drawable/ic_mysterious_box_36dp" />
<TextView
android:id="#+id/game_card_item_title"
android:textColor="#color/colorPrimaryText"
android:textAlignment="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="#style/TextAppearance.AppCompat.Title"
android:text="#string/favors_default_1" />
</LinearLayout>
</android.support.v7.widget.CardView>

Android: Recyclerview not resizing when softinput keyboard appears

I have an activity that contains a fragment and the fragment contains a customview. The customview contains an edittext and directly below it a recyclerview with height of match_parent. When the user gets focus on the edittext a softinput keyboard appears.. unfortunately this keyboard hides half the recyclerview underneath it. I want the recyclerview to resize to the remaining visible height of the screen (under the edittext) so that items in the list aren't hidden by the keyboard.
I've tried setting adjustresize for the activity in the manifest but it has no effect:
android:windowSoftInputMode="adjustResize"
I've tried setting my app theme to a base theme (in case something in my custom theme was causing a problem) - no effect:
android:theme="#style/Theme.AppCompat.NoActionBar"
I've checked to make sure there are no framelayouts anywhere down the hierarchy to the view that has to be resized (I read an SO thread that it could be a problem) - there are none.
I've checked the activity, the fragment, the customview and every adapter connected to make sure that I'm not calling getWindow anywhere (I'm not).
The customview is inflated at runtime from a viewstub. Could this have a connection?
Edit:
contents of the parent:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parent_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
...
<ViewStub
android:id="#+id/viewstub_outername"
android:layout="#layout/viewstub_thatIneed"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
contents of the viewstub:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/viewstub_root"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#android:color/white"
>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:visibility="invisible"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:visibility="invisible"
/>
</RelativeLayout>
Showing the keyboard thusly:
public static void showSoftKeyboard(Activity activity) {
View view = activity.getCurrentFocus();
InputMethodManager inputManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
}
Don't do anything in manifest file. Just use
((LinearLayoutManager)recyclerView.getLayoutManager()).setStackFromEnd(true);
This will take care of recyclerview resizing.
window.decorView.setOnApplyWindowInsetsListener { view, insets ->
val insetsCompat = toWindowInsetsCompat(insets, view)
mainNavigation.isGone = insetsCompat.isVisible(ime())
view.onApplyWindowInsets(insets)
}

ListView in Scroll View my scrollview moves to top of listview. How do I prevent this?

I have a listview in my scroll view underneath almost a page worth of scroll before that but once my listview gets populated the scrollview moves to the top of the list view. how can I fix this/prevent this from happening?
SCROLL VIEW XML:
<ScrollView
android:id="#+id/tvscrollview"
android:layout_marginTop="8.0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include
layout="#layout/a" />
<include
layout="#layout/b" />
<include
layout="#layout/c" />
<include
layout="#layout/d" />
<ListView
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
I've tried doing
sv.fullScroll(ScrollView.FOCUS_UP);
and all that stuff to my scrollview but it doesnt work
We should never put a ListView inside a ScrollView.
Work Around : When ScrollView moves up/down because of listview's notifyDataSetChanged(),
Then try,
scrollview.setEnabled(false);
listview.setFocusable(false);
adapter.notifyDataSetChanged();
scrollview.setEnabled(true);
Firstly, probably you've already heard about it, but just in case: You should never put a ListView inside a ScrollView, as ListView itself already has got a ScrollView and this design goes against the whole ListView idea. If you're convinced you have to use it, probably there's a better approach to use and you may need to simplify your code somehow.
Now, even if you still want to use something like that, you may use something like this:
package your.package.name;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
public class ScrollingListView {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
}
You simply set your adapter via .setAdapter() and afterwards call ScrollingListView.setListViewHeightBasedOnChildren(your_listview). This should redimension your window accordingly to your ListView height.
---- EDIT ----
That will be probably the ugliest workaround, but try doing the following:
ScrollView sv = (ScrollView) findViewById(R.id.your_scrollview);
sv.setEnabled(false);
// Populate your ListView
sv.setEnabled(true);
Add all the stuff on top as header to the list view.
Now that I see the code.. you can only have one ViewGroup inside a scrollview. So you would warp the two layouts into another one, BUT a ListView automatically has a scroll view in it so that wont really work.
So what you have to do is use the addHeader view in your ListActivity (of fragment) and inflate LinearLayout1 in the activity from a different xml file.
add:
android:transcriptMode="disabled"
in the list you don't want to scroll
From Android Docs
It's not possible to make a scrollable view inside a scrollable view. But as a work around this, and only in case that this listviews doesn't take much memory if all views are loaded. you can use this
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
public class NonScrollableListView extends ListView {
public NonScrollableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Do not use the highest two bits of Integer.MAX_VALUE because they are
// reserved for the MeasureSpec mode
int heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightSpec);
getLayoutParams().height = getMeasuredHeight();
}
}
Again, it's not good to use this workaround
Just Do one thing before add items in your list
listview.setFocusable(false);
after that you can again do that
listview.setFocusable(true);
if needed it will work for sure
I would wrap the list and the other layouts in a RelativeLayout instead of a LinearLayout
<ScrollView
android:id="#+id/tvscrollview"
android:layout_marginTop="8.0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<include
layout="#layout/a" />
<include
layout="#layout/b" />
<include
layout="#layout/c" />
<include
layout="#layout/d" />
</LinearLayout>
<ListView
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/container" />
</RelativeLayout>
</ScrollView>
This way the top border of the ListView is boun to the bottom border of the LinearLayout and will always stay under everything else.
You cant put the includes directly in the RelativeLayout! See here for more details.
I have made 2 or 3 changes in your xml file
<ScrollView
android:id="#+id/tvscrollview"
android:layout_marginTop="8.0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"> // This will let you see the scroll bar of list view
when you scroll your list view.
<include
layout="#layout/a" />
<include
layout="#layout/b" />
<include
layout="#layout/c" />
<include
layout="#layout/d" />
<ListView
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="300dp" />// Instead of wraping up your list, if you wish
you can give certain height to your list view.
</LinearLayout>
</ScrollView>
Another thing you need is write the given code in your java file.
onCreate()
{
....
ScrollView sView=(ScrollView)findViewById(R.id.tvscrollview);
yourListView.setOnTouchListener(new OnTouchListener()
{
public boolean onTouch(View arg0, MotionEvent arg1)
{
if(arg1.getAction() == MotionEvent.ACTION_DOWN || arg1.getAction() == MotionEvent.ACTION_MOVE)
{
sView.requestDisallowInterceptTouchEvent(true);
}
return false;
}
});
I hope this helps you.
You may want to achieve this by using following:
<LinearLayout
......>
<ScrollView
android:id="#+id/tvscrollview"
android:layout_marginTop="8.0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include
layout="#layout/a" />
<include
layout="#layout/b" />
<include
layout="#layout/c" />
<include
layout="#layout/d" />
</LinearLayout>
</ScrollView>
<ListView
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Wrap your listview outside scrollview and else inside scrollview, because You should never use a ScrollView with a ListView, because ListView takes care of its own vertical scrolling. Most importantly, doing this defeats all of the important optimizations in ListView for dealing with large lists, since it effectively forces the ListView to display its entire list of items to fill up the infinite container supplied by ScrollView.
Source Android Docs
The only solution that worked for me was to add an EditText as the first child of the layout. Ugly, I know.
<EditText
android:layout_width="0dp"
android:layout_height="0dp" />
I had the same issue I found the solution by changing the visibility of the list view in XML after setting the adapter I change the visibility to visible
listView.setAdapter(adapter);
listView.setVisibility(View.VISIBLE);
Though its a very late answer to this question and this answer has already an accepted answer, I thought putting how I solved my problem here might help others to find everything related to this problem in a single SO thread.
So here's my situation: I had a ScrollView with a ListView at the end of the layout. I know its a very bad practice to do so. I could achieve the same behaviour I wanted by attaching a header to the ListView. But anyway, my ListView got the focus when it was populated with the data and the the page was scrolled automatically to the bottom where the ListView started.
I tried with the accepted answer here, but it didn't work for me. I tried using a dummy EditText at the top of the layout so that it could request the focus automatically, but it didn't work either. Because the ListView was getting the focus after the data is loaded from a REST Api call.
Then I found this answer and this really helped. So I thought putting it in here so that others might get help from a single thread having the same problem like me.
mainScrollView.fullScroll(ScrollView.FOCUS_UP); didn't work for me either as the list was populated after the other views were populated. So I had to scroll the ScrollView to the top after the ListView is populated. So here's how I solved my problem.
mScrollView.setEnabled(false);
mIntroducerListView.setFocusable(false);
mListAdapter.notifyDataSetChanged();
// Force scroll to the top of the scroll view.
// Because, when the list view gets loaded it focuses the list view
// automatically at the bottom of this page.
mScrollView.smoothScrollTo(0, 0);
I tried the above answers, but neither of them worked. Below is my final solution.
Just override the onFinishInflate method, then do a post to scrollTo(0, 0).
#Override
protected void onFinishInflate() {
super.onFinishInflate();
this.post(new Runnable() {
#Override
public void run() {
scrollTo(0, 0);
}
});
}

Categories