Created
March 14, 2017 02:32
-
-
Save luisburgos/e298a5cb39a3de2c912eb9e84dd1b01e to your computer and use it in GitHub Desktop.
Collapsing toolbar with map fragment inside and view pager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<android.support.design.widget.CoordinatorLayout | |
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:id="@+id/information_coordinator_layout" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:fitsSystemWindows="true"> | |
<android.support.design.widget.AppBarLayout | |
android:id="@+id/appbar" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:theme="@style/AppTheme.AppBarOverlay"> | |
<android.support.design.widget.CollapsingToolbarLayout | |
android:id="@+id/collapsingToolbarLayout" | |
android:layout_width="match_parent" | |
android:layout_height="280dp" | |
app:contentScrim="?attr/colorPrimary" | |
app:expandedTitleMarginStart="48dp" | |
app:expandedTitleMarginEnd="64dp" | |
app:layout_scrollFlags="scroll|snap"> | |
<FrameLayout | |
android:id="@+id/mapContainer" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
app:layout_collapseMode="parallax"/> | |
</android.support.design.widget.CollapsingToolbarLayout> | |
<android.support.v7.widget.Toolbar | |
android:id="@+id/toolbar" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:minHeight="56dp" | |
android:background="?colorPrimary" | |
android:layout_marginTop="-56dp" | |
app:popupTheme="@style/AppTheme.PopupOverlay" | |
app:layout_scrollFlags="scroll|enterAlways|snap" /> | |
<include | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="-112dp" | |
layout="@layout/activity_model_information_header" /> | |
<android.support.design.widget.TabLayout | |
android:id="@+id/sliding_tabs" | |
android:layout_width="match_parent" | |
android:layout_height="?attr/actionBarSize" | |
app:tabIndicatorHeight="4dp" | |
app:tabMode="fixed" /> | |
</android.support.design.widget.AppBarLayout> | |
<DeactivatableViewPager | |
android:id="@+id/viewpager" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@android:color/white" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior"/> | |
</android.support.design.widget.CoordinatorLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<LinearLayout | |
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:orientation="vertical" | |
android:gravity="center" | |
app:layout_scrollFlags="scroll|enterAlways|snap"> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="112dp" | |
android:padding="6dp" | |
android:gravity="center"> | |
<TextView | |
android:id="@+id/circleView" | |
android:layout_width="100dp" | |
android:layout_height="100dp" | |
android:text="@string/name" | |
android:background="@drawable/background_circle" | |
android:textSize="18sp" | |
android:gravity="center" | |
android:textStyle="bold" | |
android:textColor="@color/white"/> | |
</LinearLayout> | |
<TextView | |
android:id="@+id/nameTextView" | |
android:layout_width="match_parent" | |
android:layout_height="28dp" | |
android:gravity="center" | |
android:text="@string/name" | |
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" /> | |
<TextView | |
android:id="@+id/descriptionTextView" | |
android:gravity="center" | |
android:layout_width="match_parent" | |
android:layout_height="28dp" | |
android:text="@string/unique_identifier" | |
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle" /> | |
</LinearLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Helper class which provides methods to being, redirect, start and finish activities. | |
*/ | |
public class ActivityHelper { | |
/** | |
* The {@code fragment} is added to the container view with id {@code frameId}. The operation is | |
* performed by the {@code fragmentManager}. | |
* | |
*/ | |
public static void addFragmentToActivity( | |
@NonNull FragmentManager fragmentManager, | |
@NonNull Fragment fragment, | |
int frameId | |
) { | |
checkNotNull(fragmentManager); | |
checkNotNull(fragment); | |
FragmentTransaction transaction = fragmentManager.beginTransaction(); | |
transaction.add(frameId, fragment); | |
transaction.commit(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ActivityModelInformation extends InformationActivity { | |
private HeaderViewHolder headerInformationHolder; | |
private TabLayout tabLayout; | |
private DeactivatableViewPager viewPager; | |
private MapViewFragment mapFragment; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_model_information); | |
super.baseSetup(); | |
setupViewPager(); | |
setupMapFragment(); | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
//CALL PRESENTER TO FETCH DATA | |
} | |
@Override | |
protected void initViews() { | |
super.initViews(); | |
viewPager = (DeactivatableViewPager) findViewById(R.id.viewpager); | |
tabLayout = (TabLayout) findViewById(R.id.sliding_tabs); | |
headerInformationHolder = new HeaderViewHolder(findViewById(android.R.id.content)); | |
//INITIALIZE PRESENTER. | |
} | |
@Override | |
protected void setInformationData() { | |
Bundle bundle = getIntent().getExtras(); | |
//SET CLASS VARIABLES from BUNDLE | |
updateUIHeader(); | |
} | |
/** | |
* This method is NOT used by this class. | |
* @param isCollapsed state of toolbar. | |
*/ | |
@Override | |
protected void onToolbarCollapsed(boolean isCollapsed) { | |
//IMPORTANT! Do nothing | |
} | |
/** | |
* Retrieves a custom activity title for display on toolbar. | |
* @return activity title. | |
*/ | |
@Override | |
public String getActivityTitle() { | |
return "Custom Activity Title"; | |
} | |
/** | |
* Updates the flowmeter header information. | |
*/ | |
private void updateUIHeader(){ | |
//UPDATE VALUES ON HEADER VIEW HOLDER | |
} | |
/** | |
* Setup the view pager that shows information about the parameters. | |
*/ | |
private void setupViewPager() { | |
//INITIALIZE THE ADAPTER | |
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { | |
public void onPageScrollStateChanged(int state) {} | |
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} | |
public void onPageSelected(int position) { | |
boolean pagingEnable = true; | |
/*if(position == MyAdapter.PAGE_NEED_IT_TO_MATCH){ | |
pagingEnable = false; | |
}*/ | |
viewPager.setPagingEnabled(pagingEnable); | |
} | |
}); | |
viewPager.setAdapter(sectionsPagerAdapter); | |
tabLayout.setupWithViewPager(viewPager); | |
} | |
/** | |
* This method setups a {@link MapViewFragment} to show the flowmeter location. | |
* This method also validates if Google Play Services are available on the current device. | |
* If there is no Google Play Services API available the map is not displayed on UI. | |
*/ | |
private void setupFlowmeterMapFragment() { | |
final int status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this); | |
if (status != ConnectionResult.SUCCESS) { | |
FrameLayout mapContainer = (FrameLayout) findViewById(R.id.mapContainer); | |
mapContainer.setVisibility(View.GONE); | |
} else { | |
mapFragment = (MapViewFragment) getSupportFragmentManager() | |
.findFragmentById(R.id.mapContainer); | |
if (mapFragment == null) { | |
mapFragment = MapViewFragment.newInstance(/* Parameters if you need */); | |
ActivityHelper.addFragmentToActivity( | |
getSupportFragmentManager(), mapFragment, R.id.mapContainer); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<shape | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
android:shape="oval"> | |
<solid android:color="@color/white" /> | |
<size | |
android:height="100dp" | |
android:width="100dp"/> | |
<padding | |
android:bottom="15dp" | |
android:top="15dp" | |
android:left="15dp" | |
android:right="15dp"/> | |
</shape> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Allows to deactivate the paging on a {@link ViewPager} component. | |
*/ | |
public class DeactivatableViewPager extends ViewPager { | |
private boolean isPagingEnabled = true; | |
public DeactivatableViewPager(Context context) { | |
super(context); | |
} | |
public DeactivatableViewPager(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
return this.isPagingEnabled && super.onTouchEvent(event); | |
} | |
@Override | |
public boolean onInterceptTouchEvent(MotionEvent event) { | |
return this.isPagingEnabled && super.onInterceptTouchEvent(event); | |
} | |
public void setPagingEnabled(boolean b) { | |
this.isPagingEnabled = b; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<RelativeLayout | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:map="http://schemas.android.com/tools" | |
android:id="@+id/supportMapContainer" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent"> | |
<FrameLayout | |
android:id="@+id/map" | |
android:name="com.google.android.gms.maps.SupportMapFragment" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
map:cameraZoom="13" | |
map:mapType="normal" | |
map:liteMode="true" /> | |
<LinearLayout | |
android:id="@+id/mapButtons" | |
android:orientation="horizontal" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_alignParentTop="true" | |
android:layout_alignParentRight="true" | |
android:layout_alignParentEnd="true" | |
android:layout_marginRight="15dip" | |
android:layout_marginEnd="15dip" | |
android:layout_marginTop="15dip"> | |
<ImageButton | |
android:id="@+id/location" | |
android:src="@drawable/ic_crosshair_gps" | |
style="@style/MapControlButton"/> | |
<ImageButton | |
android:id="@+id/zoom_in" | |
android:layout_marginLeft="5dip" | |
android:layout_marginStart="5dip" | |
android:src="@drawable/ic_plus" | |
style="@style/MapControlButton"/> | |
<ImageButton | |
android:id="@+id/zoom_out" | |
android:src="@drawable/ic_minus" | |
android:layout_marginLeft="5dip" | |
android:layout_marginStart="5dip" | |
style="@style/MapControlButton"/> | |
</LinearLayout> | |
</RelativeLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by luisburgos on 8/18/16. | |
*/ | |
public class HeaderViewHolder extends RecyclerView.ViewHolder { | |
public View cirlceView; | |
public TextView nameTextView; | |
public TextView descriptionTextView; | |
public HeaderViewHolder(View itemView) { | |
super(itemView); | |
cirlceView = itemView.findViewById(R.id.cirlceView); | |
nameTextView = (TextView) itemView.findViewById(R.id.nameTextView); | |
descriptionTextView = (TextView) itemView.findViewById(R.id.descriptionTextView); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Base UI View to show a basic information about a domain model. | |
* This class has basic components like {@link CoordinatorLayout} and | |
* {@link AppBarLayout}. | |
* Created by luisburgos on 8/31/16. | |
*/ | |
public abstract class InformationActivity extends AppCompatActivity { | |
protected CoordinatorLayout coordinatorLayout; | |
protected AppBarLayout appBarLayout; | |
protected CollapsingToolbarLayout collapsingToolbarLayout; | |
protected Toolbar toolbar; | |
/** | |
* This method has sequential cohesion in order to achieve a | |
* correct configuration for the activity. This method NEEDS to be called from | |
* concrete implementations. | |
* | |
* This method depends on {@link InformationActivity#initViews()}, | |
* {@link InformationActivity#setInformationData()}, {@link InformationActivity#setupToolbar()}, | |
* {@link InformationActivity#setupAppBar()} | |
*/ | |
protected void baseSetup(){ | |
this.initViews(); | |
this.setInformationData(); | |
this.setupToolbar(); | |
this.setupAppBar(); | |
} | |
/** | |
* BINDS xml components to class variables. | |
*/ | |
protected void initViews() { | |
coordinatorLayout = (CoordinatorLayout) findViewById(R.id.information_coordinator_layout); | |
collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout); | |
toolbar = (Toolbar) findViewById(R.id.toolbar); | |
appBarLayout = (AppBarLayout) findViewById(R.id.appbar); | |
} | |
/** | |
* Displays home back button and enables back pressed behavior. | |
*/ | |
protected void setupToolbar() { | |
setSupportActionBar(toolbar); | |
if(getSupportActionBar() != null){ | |
getSupportActionBar().setDisplayHomeAsUpEnabled(true); | |
getSupportActionBar().setDisplayShowTitleEnabled(false); | |
} | |
toolbar.setNavigationOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
onBackPressed(); | |
} | |
}); | |
} | |
/** | |
* Sets a {@link AppBarLayout.OnOffsetChangedListener} to the AppBar and notifies when | |
* offset change and is less than 25. | |
*/ | |
protected void setupAppBar() { | |
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { | |
boolean isShow = false; | |
int scrollRange = -1; | |
@Override | |
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { | |
if (scrollRange == -1) { | |
scrollRange = appBarLayout.getTotalScrollRange(); | |
} | |
if (scrollRange + verticalOffset <= 25) { | |
onToolbarCollapsed(true); | |
isShow = true; | |
} else if(isShow) { | |
onToolbarCollapsed(false); | |
isShow = false; | |
} | |
} | |
}); | |
} | |
/** | |
* Shows a {@link Snackbar} with the message to show. | |
* @param message text to show. | |
*/ | |
protected void showMessage(String message) { | |
if(coordinatorLayout == null){ | |
return; | |
} | |
Snackbar.make(coordinatorLayout, message, Snackbar.LENGTH_LONG).show(); | |
} | |
/** | |
* This method is NOT used by this class. | |
* @param isCollapsed state of toolbar. | |
*/ | |
protected abstract void onToolbarCollapsed(boolean isCollapsed); | |
/** | |
* Retrieves a custom activity title for display on toolbar. | |
* @return activity title. | |
*/ | |
protected abstract String getActivityTitle(); | |
/** | |
* This method is needed to retrieve information a set the current activity information. | |
* It could be necessary to implement a extra method to update the UI. | |
*/ | |
protected abstract void setInformationData(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Intent; | |
import android.net.Uri; | |
import android.os.Bundle; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.Fragment; | |
import android.support.v4.app.FragmentManager; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.ImageButton; | |
import com.google.android.gms.maps.CameraUpdateFactory; | |
import com.google.android.gms.maps.GoogleMap; | |
import com.google.android.gms.maps.OnMapReadyCallback; | |
import com.google.android.gms.maps.SupportMapFragment; | |
import com.google.android.gms.maps.model.BitmapDescriptorFactory; | |
import com.google.android.gms.maps.model.CameraPosition; | |
import com.google.android.gms.maps.model.LatLng; | |
import com.google.android.gms.maps.model.Marker; | |
import com.google.android.gms.maps.model.MarkerOptions; | |
/** | |
* | |
*/ | |
public class MapViewFragment extends Fragment implements OnMapReadyCallback { | |
private SupportMapFragment mapFragment; | |
private GoogleMap mMap = null; | |
private Marker mMarker; | |
private LatLng initialPoint; | |
public MapViewFragment(){ | |
//REQUIRES EMPTY CONSTRUCTOR | |
} | |
public static MapViewFragment newInstance( /* Add parameters if you need */ ){ | |
Bundle arguments = new Bundle(); | |
/*arguments.putSerializable(KEY, value);*/ | |
MapViewFragment fragment = new MapViewFragment(); | |
fragment.setArguments(arguments); | |
return fragment; | |
} | |
@Override | |
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |
View root = inflater.inflate(R.layout.fragment_model_location, container, false); | |
setupMapControlButtons(root); | |
return root; | |
} | |
@Override | |
public void onCreate(@Nullable Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
//GET VALUES FROM ARGUMENTS. | |
/*valueVariable = (String) getArguments().getSerializable(KEY);*/ | |
} | |
@Override | |
public void onActivityCreated(Bundle savedInstanceState) { | |
super.onActivityCreated(savedInstanceState); | |
FragmentManager fm = getChildFragmentManager(); | |
mapFragment = (SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map); | |
if (mapFragment == null) { | |
mapFragment = SupportMapFragment.newInstance(); | |
fm.beginTransaction().replace(R.id.map, mapFragment).commit(); | |
} | |
} | |
@Override | |
public void onResume() { | |
super.onResume(); | |
mapFragment.getMapAsync(this); | |
} | |
@Override | |
public void onMapReady(GoogleMap googleMap) { | |
this.mMap = googleMap; | |
initialPoint = /* IMPORTANT!! FIND A WAY TO PARSE A LAT LNG POSITION*/ | |
if(initialPoint != null){ | |
setupMarker(initialPoint); | |
setupMarkerInfoAction(); | |
} | |
} | |
private void setupMarkerInfoAction() { | |
mMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() { | |
@Override | |
public void onInfoWindowClick(Marker marker) { | |
displayOpenOnGoogleMapsDialog(); | |
} | |
}); | |
} | |
private void displayOpenOnGoogleMapsDialog() { | |
//IMPORTANT! Display a Dialog to Open on Google Maps. | |
} | |
private void zoomToCurrentLatLngPosition(LatLng initialPoint) { | |
CameraPosition cameraPosition = new CameraPosition.Builder() | |
.target(initialPoint) | |
.zoom(9) | |
.build(); | |
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); | |
} | |
private void setupMarker(@NonNull LatLng initialPoint) { | |
this.mMarker = this.mMap.addMarker( | |
new MarkerOptions() | |
.position(initialPoint) | |
.title(yourCustomTitleHere) | |
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_custom_marker_of_your_choice)) | |
); | |
mMarker.showInfoWindow(); | |
zoomToCurrentLatLngPosition(initialPoint); | |
} | |
private void setupMapControlButtons(View root) { | |
final ImageButton locationButton = (ImageButton) root.findViewById(R.id.location); | |
final ImageButton zoomInButton = (ImageButton) root.findViewById(R.id.zoom_in); | |
final ImageButton zoomOutButton = (ImageButton) root.findViewById(R.id.zoom_out); | |
locationButton.setVisibility(View.VISIBLE); | |
zoomInButton.setVisibility(View.VISIBLE); | |
zoomOutButton.setVisibility(View.VISIBLE); | |
locationButton.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View view) { | |
if(initialPoint != null){ | |
zoomToCurrentLatLngPosition(initialPoint); | |
} | |
} | |
}); | |
zoomInButton.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View view) { | |
mMap.animateCamera(CameraUpdateFactory.zoomIn()); | |
} | |
}); | |
zoomOutButton.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View view) { | |
mMap.animateCamera(CameraUpdateFactory.zoomOut()); | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<resources> | |
<style name="MapControlButton"> | |
<item name="android:layout_width">25dip</item> | |
<item name="android:layout_height">25dip</item> | |
<item name="android:visibility">gone</item> | |
<item name="android:background">@drawable/background_dodgerblue_rounded_corners</item> | |
</style> | |
</resources> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment