How can I display a message at a specific location in a Google Maps Activity on Android without adding a marker? I just want to display a small pop up animation containing a message at specific coordinates.
Are there any GitHub libraries that can perform this specific task?
You can place any View over MapFragment (or MapView) and animate it as you wish with Animations: animate size, position, transparency etc., use various interpolators and merge several animations into one via AnimatorSet. To get screen position of the View for specific LatLng coordinates you can use Projection.toScreenLocation() method.
For example, for "Hello World" TextView with "popup" animation over the map, you can use code like that:
activity_main.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"
tools:context="activities.MainActivity">
<fragment class="com.google.android.gms.maps.SupportMapFragment"
android:id="#+id/map_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="#+id/popup_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:visibility="invisible"
android:text="Hello World!"/>
</RelativeLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
private GoogleMap mGoogleMap;
private SupportMapFragment mMapSupportedFragment;
private TextView mPopUpTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPopUpTextView = (TextView) findViewById(R.id.popup_view);
mMapSupportedFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map_fragment);
mMapSupportedFragment.getMapAsync(MainActivity.this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
// get screen position for latLng
Projection projection = mGoogleMap.getProjection();
Point origin = projection.toScreenLocation(latLng);
// popup TextView
popUpView(origin, mPopUpTextView, 500);
}
});
}
public void popUpView(final Point origin, final View view, long duration){
view.setX(origin.x);
view.setY(origin.y);
view.setVisibility(View.VISIBLE);
ValueAnimator sizeAnimation = ValueAnimator.ofInt(0, view.getMeasuredHeight());
sizeAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
sizeAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = val;
view.setLayoutParams(layoutParams);
}
});
sizeAnimation.setDuration(duration);
ValueAnimator positionAnimation = ValueAnimator.ofInt(0, view.getMeasuredHeight());
positionAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
positionAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
view.setY(origin.y - val);
}
});
positionAnimation.setDuration(duration);
AnimatorSet popUpSet = new AnimatorSet();
popUpSet.play(sizeAnimation).with(positionAnimation);
popUpSet.start();
}
}
Result:
I would suggest you go with marker only.
As marker it self gives some features like animation and all.
You can also customize the marker in different way to show the text and not the image and also you can user the customized text like html text show more decorated text backed by html and css.
This one is simple and great solution as i have also used the same in of my project.
Related
It's been days of researching and I cannot figure out a way to do it.
Here is the link of the library on Github. Library
public class PDFViewActivity1 extends AppCompatActivity {
LinearLayout root;
EditText etPdfUrl;
Button btnDownload;
PDFPagerAdapter adapter;
String id;
ArrayList<String> topicLink;
File file;
String filePath;
PDFViewPager pdfViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_p_d_f_view);
root = (LinearLayout) findViewById(R.id.remote_pdf_root);
final Context ctx = this;
Intent intent = getIntent();
String str = intent.getStringExtra("filePath");
str = str; // This contains the path of the PDF on my device
Log.i("filePathInString", str);
pdfViewPager = new PDFViewPager(ctx, str);
pdfViewPager.setId(R.id.pdfViewPager);
pdfViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
adapter = new PDFPagerAdapter(ctx, str);
pdfViewPager.setAdapter(adapter);
root.removeAllViewsInLayout();
root.addView(pdfViewPager,
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
}
#Override
protected void onDestroy() {
super.onDestroy();
((PDFPagerAdapter) pdfViewPager.getAdapter()).close();
}
}
The PDF renders perfectly form my device but I cannot see the page numbers, title , total pages of the PDF when the PDF is loaded.
This is my XML file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/remote_pdf_root"
android:orientation="vertical"
android:background="#FFFFFF"
tools:context=".PDFViewActivity1"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<es.voghdev.pdfviewpager.library.PDFViewPager
android:id="#+id/pdfViewPager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
What do I do when the page is scrolled, I cannot figure out a thing , I tried a lot of methods of the PDFAdapter but I an unsuccessful :( How can I do the task ?
RelativeLayout remotePdfRoot = findViewById(R.id.remote_pdf_root);
remotePDFViewPager = new RemotePDFViewPager(this, downloadFileUrlConnection, url, listener);
remotePDFViewPager.setId(R.id.pdfViewPager);
//after file loading success
PDFPagerAdapter adapter = new PDFPagerAdapter(this, FileUtil.extractFileNameFromURL(url));
remotePDFViewPager.setAdapter(adapter);
updateLayout();
private void updateLayout() {
remotePdfRoot.removeAllViewsInLayout();
remotePdfRoot.addView(remotePDFViewPager, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
}
I preview pdf this way and there will be a pagenumber.
You can use https://github.com/barteksc/AndroidPdfViewer library for this and you can get the page count by
`vpPdf.fromAsset("sample.pdf").onError {
Log.i(TAG, "${it.localizedMessage}")
it.printStackTrace()
}.onPageError { _, t ->
t.printStackTrace()
}.enableSwipe(true).swipeHorizontal(true).onPageChange { page, pageCount ->
//here page count is count of page user currently is viewing.
}.load()`
I had to use this lib at work and it is working perfectly fine!!
The above code is from kotlin but you can convert it to java i guess,If you are not able to convert it the kindly comment so i will help you with that too!!.
In my app, I have a button to show a drop-down menu, inside of that menu we have some options, one of this is "flip A coin",
the purpose of this option is to flip a coin easy animation, that animation appears inside a textView, and show a head-side or a tail-side of a coin instead of the text in the textView.
I have two problems:
The animation doesn't work how I want, it should appear in 1 second a coin instead of the text inside the textView, it stays there and after 2 seconds he disappears, but after the disappearance, the coin image come back inside the textView, it shouldn't reappear.
This is not a real question for a problem but more an optional question like "you know how to do that?". I 'don't know how to create a flip animation with a coin multiple rotations.
XML drop down menu:
<item
android:id="#+id/flipacoin"
android:title="#string/flipACoin" />
<item
android:id="#+id/rolladice"
android:title="#string/rollADice" />
<item
android:id="#+id/imagebackground"
android:title="#string/changeImage" />
JAVA code that calls the animation function:
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
case R.id.flipacoin:
flipACoin();
return true;
case R.id.rolladice:
Toast.makeText(this,"TODO roll a dice",Toast.LENGTH_SHORT).show();
return true;
case R.id.imagebackground:
Toast.makeText(this,"TODO image background",Toast.LENGTH_SHORT).show();
return true;
default:
return false;
}
}
JAVA animation function:
public void flipACoin(){
coin.setText(null); //this is for remove the text inside the textView
coin.setBackground(RANDOM.nextFloat() > 0.5f ? getResources().getDrawable(R.drawable.tails) : getResources().getDrawable(R.drawable.heads));
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(1000);
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setStartOffset(2000);
fadeOut.setDuration(1000);
AnimationSet animation = new AnimationSet(false);
animation.addAnimation(fadeIn);
animation.addAnimation(fadeOut);
coin.setAnimation(animation);
}
When You set background at the beginning it just stays after animation. To set back text and background to null You can add Animation listener. Below is sample application which does it:
public class MainActivity extends AppCompatActivity
{
TextView coin;
Random RANDOM;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RANDOM = new Random();
coin = findViewById(R.id.coin);
(findViewById(R.id.click)).setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
flipACoin();
}
});
}
public void flipACoin()
{
coin.setText(null);
coin.setBackground(ResourcesCompat.getDrawable(getResources(),
RANDOM.nextFloat() > 0.5f ? R.drawable.ic_launcher_background : R.drawable.ic_launcher_foreground,
null
));
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(1000);
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setStartOffset(2000);
fadeOut.setDuration(1000);
AnimationSet animation = new AnimationSet(false);
animation.addAnimation(fadeIn);
animation.addAnimation(fadeOut);
// listener, it will execute function when animation starts/ends/repeats
animation.setAnimationListener(new Animation.AnimationListener()
{
#Override
public void onAnimationStart(Animation animation)
{
Log.d("MyTag", "onAnimationStart:");
}
#Override
public void onAnimationEnd(Animation animation) // when animation ends, set text and background to null
{
Log.d("MyTag", "onAnimationEnd:");
coin.setBackground(null);
coin.setText("Default");
}
#Override
public void onAnimationRepeat(Animation animation)
{
Log.d("MyTag", "onAnimationRepeat:");
}
});
coin.setAnimation(animation);
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:id="#+id/click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click"
/>
<TextView
android:id="#+id/coin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Default"
/>
</androidx.appcompat.widget.LinearLayoutCompat>
Sorry for the noob question but I did not come across any situations that would work for me. Im sure this is super simple, I just need to be pointed in the right direction.
Objective:
I want to be able to take the name of what the user specified and add it to the markers title.
What I know:
I am unable to inflate the xml and grab it via that way cause the method is being override and if I inflate to my knowledge will no longer allow me to override the method. How should I approach this?
MapsAcitivy
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, addPlace.Communicator {
private GoogleMap mMap;
public static final int MY_PERMISSION_ACCESS_FINE_LOCATION = 0;
int mStackLevel;
int YES_NO_CALL;
FragmentManager manager = getSupportFragmentManager();
final Context context = this;
#InjectView(R.id.btn_login) Button _loginButton;
ClusterManager<ClusterRequest> mClusterManager;
class CustomInfoWindowAdapter implements GoogleMap.InfoWindowAdapter {
// These are both viewgroups containing an ImageView with id "badge" and two TextViews with id
// "title" and "snippet".
private final View mWindow;
//private final View mContents;
CustomInfoWindowAdapter() {
mWindow = getLayoutInflater().inflate(R.layout.info_window_layout, null);
//mContents = getLayoutInflater().inflate(R.layout.custom_info_contents, null);
}
#Override
public View getInfoWindow(Marker marker) {
render(marker, mWindow);
return mWindow;
}
#Override
public View getInfoContents(Marker marker) {
// Getting view from the layout file info_window_layout
View v = getLayoutInflater().inflate(R.layout.info_window_layout, null);
// Getting the position from the marker
LatLng latLng = marker.getPosition();
// Getting reference to the TextView to set latitude
TextView tvLat = (TextView) v.findViewById(R.id.tv_lat);
// Getting reference to the TextView to set longitude
TextView tvLng = (TextView) v.findViewById(R.id.tv_lng);
// Setting the latitude
tvLat.setText("Latitude:" + latLng.latitude);
// Setting the longitude
tvLng.setText("Longitude:"+ latLng.longitude);
// Returning the view containing InfoWindow contents
return v;
//render(marker, mContents);
//return mContents;
}
private void render(Marker marker, View view) {
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
#TargetApi(23)
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSION_ACCESS_FINE_LOCATION);
// MY_PERMISSION_ACCESS_FINE_LOCATION is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
LocationManager initialLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
String initialProvider = initialLocationManager.getBestProvider(criteria, true);
Location initialLocation = initialLocationManager.getLastKnownLocation(initialProvider);
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
double initialLatitude = initialLocation.getLatitude();
double initialLongitude = initialLocation.getLongitude();
LatLng initialLatLng = new LatLng(initialLatitude, initialLongitude);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(initialLatLng, 14.9f));
//mMap.setOnInfoWindowClickListener(this);
mClusterManager = new ClusterManager<ClusterRequest>(getApplicationContext(), mMap);
mMap.setOnCameraChangeListener(mClusterManager);
mMap.setOnMarkerClickListener(mClusterManager);
}
}
public void onButtonClick(View view){
//do something when button is clicked.
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.add_place);
dialog.setTitle("Add Place");
Button btnLogin = (Button) dialog.findViewById(R.id.addPlacebtnSubmit);
Button btnCancel = (Button) dialog.findViewById(R.id.btnCancel);
final EditText txtUsername = (EditText)dialog.findViewById(R.id.txtStopName);
// Attached listener for add place GUI button
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String stopName = txtUsername.getText().toString();
if(stopName.length() > 4){
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(MapsActivity.this,
android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(MapsActivity.this,
android.Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(MapsActivity.this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSION_ACCESS_FINE_LOCATION);
// MY_PERMISSION_ACCESS_FINE_LOCATION is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
LocationManager currentLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria currentCriteria = new Criteria();
String currentProvider = currentLocationManager.getBestProvider(currentCriteria, true);
Location currentLocation = currentLocationManager.getLastKnownLocation(currentProvider);
double currentLatitude = currentLocation.getLatitude();
double currentLongitude = currentLocation.getLongitude();
LatLng currentLatLng = new LatLng(currentLatitude, currentLongitude);
ClusterRequest testCluster = new ClusterRequest(currentLatitude, currentLongitude);
mClusterManager.addItem(testCluster);
mClusterManager.setRenderer(new MapIconRender(getApplicationContext(), mMap, mClusterManager));
dialog.dismiss();
}
else{
txtUsername.setError("Stop name must be at least 5 characters long.");
}
}
});
}
MapIconRender.java
public class MapIconRender extends DefaultClusterRenderer<ClusterRequest> {
public MapIconRender(Context context, GoogleMap map,
ClusterManager<ClusterRequest> clusterManager) {
super(context, map, clusterManager);
}
#Override
protected void onBeforeClusterItemRendered (ClusterRequest item, MarkerOptions
markerOptions){
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.map_marker_outside_azure));
markerOptions.snippet("Status: ");
markerOptions.title(stopName); //<------ THIS IS WHERE I WANT THE STOP NAME TO BE WHAT THE USER ENTERED.
super.onBeforeClusterItemRendered(item, markerOptions);
}
}
add_place.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_height="match_parent"
android:paddingLeft="10dp" android:paddingRight="10dp"
android:background="#fff" android:layout_width="300dp"
android:paddingTop="10dp">
<View
android:id="#+id/HorizontalLine"
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="#aaa" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Name:"
android:paddingTop="20dp"
android:id="#+id/name" />
<EditText android:layout_height="wrap_content"
android:id="#+id/txtStopName"
android:maxLength="100"
android:singleLine="true"
android:hint="Name of this stop (5-100 characters)"
android:layout_width="match_parent">
<requestFocus></requestFocus>
</EditText>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Type:"
android:paddingTop="20dp"
android:layout_marginBottom="10dp"
android:id="#+id/type" />
<Spinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/spinner"
android:entries="#array/type_arrays"
android:prompt="#string/type_prompt"
android:layout_marginBottom="10dp"/>
<View
android:id="#+id/HorizontalLine2"
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="#aaa" />
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content" android:id="#+id/linearLayout1"
android:paddingTop="5dp">
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_weight="0.5"
android:id="#+id/btnCancel" android:text="Cancel"
android:onClick="addPlaceCancel"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_weight="0.5"
android:id="#+id/addPlacebtnSubmit" android:text="Submit"
android:onClick="addPlaceSubmit"
android:layout_marginBottom="10dp"/>
</LinearLayout>
</LinearLayout>
ClusterRequest.java
public class ClusterRequest implements ClusterItem {
private final LatLng mPosition;
public ClusterRequest(double lat, double lng) {
mPosition = new LatLng(lat, lng);
}
#Override
public LatLng getPosition() {
return mPosition;
}
}
Can't you override onClusterItemRendered() method?
I think you can save your marker name in onBeforeClusterItemRendered() to any class-global variable String, and set the marker name in onClusterItemRendered() with Marker.setTitle(yourSavedTitle); or something.
Something like this:
public class MapIconRender extends DefaultClusterRenderer<ClusterRequest> {
private String mMarkerTitle;
public MapIconRender(Context context, GoogleMap map,
ClusterManager<ClusterRequest> clusterManager) {
super(context, map, clusterManager);
}
#Override
protected void onBeforeClusterItemRendered (ClusterRequest item, MarkerOptions
markerOptions){
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.map_marker_outside_azure));
markerOptions.snippet("Status: ");
markerOptions.title(stopName); //<------ THIS IS WHERE I WANT THE STOP NAME TO BE WHAT THE USER ENTERED.
mMarkerTitle = stopName;
super.onBeforeClusterItemRendered(item, markerOptions);
}
#Override
protected void onClusterItemRendered (ClusterRequest item, Marker marker){
marker.setTitle(mMarkerTitle);
}
}
#SuhyeonLee Not sure if this is what you meant (please let me know) but I did find the answer surprisingly enough in the demo that google released for their customize cluster demo. Heres what I learned. When calling the MapIconRender.java class via
mClusterManager.setRenderer(new MapIconRender(getApplicationContext(), mMap, mClusterManager));
Which will run this method in the MapIconRender.java class
protected void onBeforeClusterItemRendered (ClusterRequest item, MarkerOptions
markerOptions)
Which means whatever variables in the ClusterRequest class will be accessible here in the MapIconRender.java class and can be accessed via (item.variableName). I apologize for not posting the code for the file ClusterRequest, I didnt think it was needed. ill go back and add that snippet to my original question.
Anyway the new code I needed to add was as follows:
In the MapsActivity class I needed to pass the ClusterRequest class the name of the marker(or title of the marker) via:
ClusterRequest testCluster = new ClusterRequest(currentLatitude, currentLongitude, stopName); //stopName was added here.
And in the ClusterRequest class I needed to add the "global variable" of the marker name (aka stopName) via:
public class ClusterRequest implements ClusterItem {
private final LatLng mPosition;
public final String stopName; //Add a "global variable" here so it can be accessible in the MapIconRender class.
public ClusterRequest(double lat, double lng, String _stopName) {
mPosition = new LatLng(lat, lng);
stopName = _stopName;
}
#Override
public LatLng getPosition() {
return mPosition;
}
}
And finally in my MapIconRender.java class I can add the title name of the marker via:
public class MapIconRender extends DefaultClusterRenderer<ClusterRequest> {
public MapIconRender(Context context, GoogleMap map,
ClusterManager<ClusterRequest> clusterManager) {
super(context, map, clusterManager);
}
#Override
protected void onBeforeClusterItemRendered (ClusterRequest item, MarkerOptions
markerOptions){
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.map_marker_outside_azure));
markerOptions.snippet("Status: ");
markerOptions.title("Title: " + item.stopName); //Now we can access the title of the marker by calling item.variableName
super.onBeforeClusterItemRendered(item, markerOptions);
}
}
Im really sorry about the noob question here but I hope this helps someone out that may have the same question as I did and thank you for your answers! "SO" community is awesome!
Imagine a number 10, then after user clicks a button it changes to 100. But how to make an efficient transition
10 -> 100,
that will display values like
12, 15, 18, ..., 97, 100 over 1 second.
I've seen something like that in "Cookie clicker" but couldn't find anything about that kind of transition in the source code.
I had an idea of a loop (for number1 < number2, do number1++), it will work fine for small numbers, but if 10 changes to 1 billion, then the loop will probably freeze the whole app.
Second idea is to get added value (100-10=90) and divide by 30 or 60 frames, and add this value with each frame. But what will happen if frame is dropped? - Probably value will not be added. What if user makes double click or the system adds values automatically?
Hope it gives an idea of what kind of number transition I need.
Maybe I overlooked and there is a simple approach? Any help is appreciated.
Hope this little demo using a ValueAnimator will inspire you to find an appropriate solution.
You can specify the duration of the animation (see code) and even adjust the frame-rate by saying mAnimator.setFrameDelay(frameDelay);.
By using animator.isRunning() or animator.isStarted() you can prevent double-click malfunction or other unwanted behaviour while the current animation is runnning.
The Main Activity:
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
tv.setText(String.format("%04d", value));
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animator) {
super.onAnimationEnd(animator);
final int endValue = Integer.parseInt((String) tv.getText());
mAnimator.setIntValues(endValue, endValue + 100);
}
});
}
/** Button callback */
public void onClick(final View view) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
mAnimator.start();
}
}
}
Simple demo layout:
<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" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100"
android:onClick="onClick">
</Button>
Here's another demo (hope this answers your 2. question), which implements different behaviour dependent on single click or double-click on the button. Just experiment with it, you now have the basic building blocks to construct own behavour ...
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
TextView mTv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
mTv.setText(String.format("%04d", value));
}
});
final Button button = (Button) findViewById(R.id.button);
final GestureDetector gestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDoubleTap(MotionEvent e) {
performAnimation(100);
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
performAnimation(0);
return true;
}
});
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
}
/** starts animation */
private void performAnimation(final int offset) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
final int endValue = Integer.parseInt((String) mTv.getText());
mAnimator.setIntValues(endValue + offset, endValue + 100 + offset);
mAnimator.start();
}
}
}
Don't forget to replace your layout file, since the click-attribute of the button has been removed:
<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" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100" >
</Button>
</LinearLayout>
I guess you can do it by using different threads. Only main thread works with UI so you can divide the interval into small intervals and make a transitions in different threads.After send them to main thread and print. Hope it will help.
I'm making an app that just displays a clock, but I want is so that everytime a user touches the screen it changes the color of the text (from a list of preselected colors in a colors.xml file) but I haven't got a clue where to start. Can someone point me in the right direction?
Here's the main activity:
public class MainActivity extends Activity {
private static final Random RANDOM = new Random();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
Handler handler = new RandomMoveHandler((TextView) findViewById(R.id.digitalClock1));
handler.sendEmptyMessage(0);
}
// Make the handler subclass static because of this: http://stackoverflow.com/a/11408340/111777
private static class RandomMoveHandler extends Handler {
private final WeakReference<TextView> textViewWeakReference;
private RandomMoveHandler(TextView textView) {
this.textViewWeakReference = new WeakReference<TextView>(textView);
}
#Override
public void handleMessage(Message msg) {
TextView textView = textViewWeakReference.get();
if (textView == null) {
Log.i(TAG, "WeakReference is gone so giving up.");
return;
}
int x = RANDOM.nextInt(350 - 100);
int y = RANDOM.nextInt(800 - 100);
Log.i(TAG, String.format("Moving text view to (%d, %d)", x, y));
textView.setX(x);
textView.setY(y);
//change the text position here
this.sendEmptyMessageDelayed(0, 30000);
}
}
private static final String TAG = MainActivity.class.getSimpleName();
}
and here's the layout xml:
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity"
android:background="#color/black" >
<DigitalClock
android:id="#+id/digitalClock1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DigitalClock"
android:textColor="#color/ics_blue"
android:textSize="28sp" />
I haven't making deal with DigitalClock but I think, at first, you should reference DigitalClock variable, not TextView. And second, to intercept touch event you need to override onTouckEvent method of your activity, it will callback everytime user touches the screen.
You should follow these steps
Use a TimerTask to.continusly show the time
Implement a touchlistener on that clock view
like this
view.setOnTouchListener
Make an array Colors like this
int[] colr={Color.BLACK,Color.BLUE};
and use random index in your touch event andset it as your color of the view