I'm developing in google maps APIv2. The issue that I'm facing now is I only able to add in one line of word in info windows/snippet. But the output that I want is able to display in break line form as example show below. So is there any possible methods to solve it?
Example:
Coordinate: 03.05085, 101.70506
Speed Limit: 80 km/h
public class MainActivity extends FragmentActivity {
static final LatLng SgBesi = new LatLng(03.05085, 101.76022);
static final LatLng JB = new LatLng(1.48322, 103.69065);
private GoogleMap map;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
map.addMarker(new MarkerOptions().position(SgBesi)
.title("KM D7.7 Sungai Besi") //name
.snippet("Coordinate: 03.05085, 101.70506")); //description
map.addMarker(new MarkerOptions().position(JB)
.title("test")
.snippet("Hey, how are you?"));
// .icon(BitmapDescriptorFactory //set icon
// .fromResource(R.drawable.ic_launcher)));
// move the camera instantly with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(SgBesi, 15));
// zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomTo(15), 2000, null);
}
}
You need to use a custom InfoWindowAdapter to change the layout of InfoWindow to a custom design defined using a layout file. Basically you need to :
Declare your function using GoogleMap.setInfoWindowAdapter(Yourcustominfowindowadpater)
Have a class like below:
...
class Yourcustominfowindowadpater implements InfoWindowAdapter {
private final View mymarkerview;
Yourcustominfowindowadpater() {
mymarkerview = getLayoutInflater()
.inflate(R.layout.custominfowindow, null);
}
public View getInfoWindow(Marker marker) {
render(marker, mymarkerview);
return mymarkerview;
}
public View getInfoContents(Marker marker) {
return null;
}
private void render(Marker marker, View view) {
// Add the code to set the required values
// for each element in your custominfowindow layout file
}
}
I would like to add something to #tony , According to documentation you cant add action to your custom view as it draw as image in run time.
Note: The info window that is drawn is not a live view. The view is
rendered as an image (using View.draw(Canvas)) at the time it is
returned. This means that any subsequent changes to the view will not
be reflected by the info window on the map. To update the info window
later (for example, after an image has loaded), call showInfoWindow().
Furthermore, the info window will not respect any of the interactivity
typical for a normal view such as touch or gesture events. However you
can listen to a generic click event on the whole info window as
described in the section below.
You will have to use InfoWindowAdapter to create custom info windows. The default implementation somehow removes newlines from snippet, which might be considered a minor bug.
Related
In a MvvmCross app, I have a page with the classic chat behavior (WhatsApp like): this page shows the history of messages exchanged between two users with the last message at the bottom of the list.
I've successfully implemented the view in Windows Phone 8.1, but I'm struggling with a problem in Android.
I'll give you a short introduction and description of my problem and next I'll go through technical details.
INTRODUCTION
Actually, my need is to apply different style to messages sent by different users: tipically align left messages sent from other user and align right messages sent by me (I do this through the weight property); I need to apply a different drawable background and set different gravity property also.
I use custom binding because, AFAIK, those properties cannot be binded with classic binding: local:MvxBind="Gravity MyPropery" doesn't work because there is no Gravity property.
So, I have of course two axml files:
the first one contains the Mvx.MvxListView
the second one contains the item template for MvxListView
And I've created three different custombinding (for Background, Gravity and Weight) following these guides:
http://slodge.blogspot.it/2013/06/n28-custom-bindings-n1-days-of-mvvmcross.html
In MvvmCross how do I do custom bind properties
THE PROBLEM
I want that, when a user opens the chat View, the list widget shows automatically the last message. To accomplish this, I scroll programmatically the list to the last message and this seems to be the problem.
If I don't scroll programmatically, when I open the page and scroll manually to the end of the page, all custom bindings are applied successfully: I can see messages aligned right and left, with correct background and weight applied.
If I force the scroll programmatically, when I open the page I see a strange behavior: all the messages are present (classic binding, such as Text property, have been successfully applied), but custom bindings are missing. All the messages have the same background and are all left aligned.
BUT, if I scroll manually up and down, the custom binding are processed and the messages are displayed with right style.
DEBUG ANALYSIS
To debug the behaviour I've put a simple static counter in a custom binding procedure to track every time the function is processed.
public class LinearLayoutWeightTargetBinding : MvxAndroidTargetBinding
{
public static int debugCounter = 0;
public LinearLayoutWeightTargetBinding(object target) : base(target)
{
}
protected LinearLayout MyTarget
{
get { return (LinearLayout)Target; }
}
public override Type TargetType { get { return typeof(bool); } }
protected override void SetValueImpl(object target, object value)
{
var ll = (LinearLayout)target;
var itsMe = (bool)value;
var weight = itsMe ? (float)20.0 : (float)5.0;
var layoutParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WrapContent, weight);
ll.LayoutParameters = layoutParams;
Log.Debug("MeeCHAT", string.Format("LinearLayoutWeightTargetBinding::SetValueImpl::ItsMe:{0} - counter:{1}", itsMe, ++debugCounter));
}
public override MvxBindingMode DefaultMode { get {return MvxBindingMode.TwoWay;} }
}
By this way I saw that actually by scrolling up and down the custom bindings are applied (debugCounter increases correctly).
BUT when I apply the programmatically scroll, only the first 10 items are processed by the custom bindings and this seems the reason why I see the messages without the right style. Because I have a long list, only the first 10 items are processed but they are not visible (they are out of the visible area) and the visibile items have not been processed.
TECHNICAL DETAILS
Here are some details related to technical aspects of my app. I try to give you all important aspects.
ORGANIZATION OF THE VIEWS
By following the approach described by Greg Shackles in this article http://gregshackles.com/presenters-in-mvvmcross-navigating-android-with-fragments/ I have just one general Activity for the app and one Fragment for each View; then through a Presenter is possible to activate the right ViewModel and manage the stack of the navigation.
The Fragment for the View where I have the Mvx.MvxListView widget is
public class MyMatchersChatView : MvxFragment
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignore = base.OnCreateView(inflater, container, savedInstanceState);
var result = this.BindingInflate(Resource.Layout.MyMatchersChatView, null);
var headerFrame = result.FindViewById<FrameLayout>(Resource.Id.headerFrameMyMatchersChatView);
var headerWidget = new HeaderWidget() { ViewModel = this.ViewModel };
var tran = ChildFragmentManager.BeginTransaction();
tran.Add(headerFrame.Id, headerWidget, "headerMyMatchersChat");
tran.Commit();
var listView = result.FindViewById<MvxListView>(Resource.Id.messagesList);
listView.SetSelection(listView.Adapter.Count - 1); // Scroll to the end of the list
return result;
}
}
The statement listView.SetSelection(listView.Adapter.Count - 1); force the list to scroll to the end.
Last two things: how the custom bindings are registered and how are applied in axml file.
REGISTRATION OF CUSTOM BINDING
In Setup.cs I have:
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
base.FillTargetFactories(registry);
registry.RegisterFactory(new MvxCustomBindingFactory<LinearLayout>("CustomWeight",
(b) => new LinearLayoutWeightTargetBinding(b)));
}
APPLYING OF CUSTOM BINDING
In my axml I have:
<LinearLayout
android:orientation="horizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
local:MvxBind="CustomWeight IsCurrentUser">
LISTVIEW AND VIEWMODEL
Here is the code of ListView
<Mvx.MvxListView
android:id="#+id/messagesList"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
local:MvxBind="ItemsSource MyMessages"
local:MvxItemTemplate="#layout/mymatcherschatview_itemtemplate" />
and the property in ViewModel
private IEnumerable<MyMatchMessageModel> _myMessages;
public IEnumerable<MyMatchMessageModel> MyMessages
{
get { return _myMessages; }
set
{
_myMessages = value;
RaisePropertyChanged(() => MyMessages);
}
}
ENVIRONMENT
Finally, here is my environment:
Visual Studio 2015
MvvmCross 3.5.1
Core targets: .NET Framework 4.5, Windows 8, ASP.NET Core 5.0, Windows Phone 8.1, Xamarin.Android, Xamarin.iOS, Xamarin.iOS (Classic)
The Android app target is API Level 19 (Xamarin.Android v4.4 Support)
Xamarin 3.11.1450.0
Xamarin.Android 5.1.6.7
Someone can help me to understand if I'm doing something wrong?
Thanks for reading and for any help!
>>EDIT 1<<
I've changed my layout by adding stackFromBottom and transcriptMode properties and by removing the scrolling to below programmatically in Fragment obtaining an auto-scroll behavior, but the problem still remains: to see messages with correct style I have to manually scroll up and down (to activate the custom bindings)
Here is the new axml...
<Mvx.MvxListView
android:id="#+id/messagesList"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll"
local:MvxBind="ItemsSource MyMessages"
local:MvxItemTemplate="#layout/mymatcherschatview_itemtemplate" />
...and the new code in Fragment
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignore = base.OnCreateView(inflater, container, savedInstanceState);
var result = this.BindingInflate(Resource.Layout.MyMatchersChatView, null);
var headerFrame = result.FindViewById<FrameLayout>(Resource.Id.headerFrameMyMatchersChatView);
var headerWidget = new HeaderWidget() { ViewModel = this.ViewModel };
var tran = ChildFragmentManager.BeginTransaction();
tran.Add(headerFrame.Id, headerWidget, "headerMyMatchersChat");
tran.Commit();
return result;
}
First thing I would do is to make sure that your custom binding is always getting called.
Set a breakpoint on the SetValueImpl() method and check it´s getting called on those problematic items. If that happens, then the issue relies on the view no getting updated for any reason and you should work on that. If it doesn´t break, you will know for sure it´s a custom binding problem (possibly a bug) in MvxAdapter.
If you find out it´s the second one. I would suggest getting rid of your custom binding and creating your own ChatListAdapter : MvxAdapter as follows:
public class CoolChatListAdapter : MvxAdapter
{
public CoolChatListAdapter(Context context, IMvxAndroidBindingContext bindingContext) : base(context, bindingContext)
{
}
protected override View GetBindableView(View convertView, object source, int templateId)
{
var item = source as MyMatchMessageModel;
var weight = item.IsCurrentUser ? (float) 20.0 : (float) 5.0;
var ll = (LinearLayout) convertView;
var layoutParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WrapContent, weight);
ll.LayoutParameters = layoutParams;
return base.GetBindableView(convertView, source, templateId);
}
}
Then, in your android view:
var adapter = new ChatListAdapter(this, (IMvxAndroidBindingContext)BindingContext);
_chatList = FindViewById<MvxListView>(Resource.Id.chat_list_view);
_chatList.Adapter = adapter;
I am new to automation and want to create an automation test which can do following:
Open one tab --- click and get some info from that tab
Switch to another tab --- click and get some info from this tab now.
Compare the infos.
We use Page Object Model to get info from one page. However the moment, I switch to another tab -- it switches the tab successfully but does not locate any element on it.
Any idea ?
Questions I would ask is,
Is the element locator correct?
Is this a unique element locator?
Is this a synchronization issue? Are you waiting enough for the page to load before finding the element?
Is this problem particular to a browser? Is it consistent across?
Also make sure you pass on the driver object from one page object to the other. Like,
public class PageOne {
public PageOne(WebDriver driver) {
//do something in constructor
}
public void someMethodInPage1() {
driver.findElement(By.id("button1")).click();
PageTwo pageTwo = new PageTwo(driver);
pageTwo.someMethodInPage2();
}
}
public class PageTwo {
private WebDriver driver;
public PageTwo(WebDriver driver) {
//do something in constructor
this.driver = driver;
}
public void someMethodInPage2() {
driver.findElement(By.id("button2")).click();
}
}
In the WinRt/WP 8.1 MapControl, how do I differentiate between when the user changed the center of the screen by swiping vs a programmatic change?
The WinRt/WP 8.1 MapControl has a CenterChanged event ( http://msdn.microsoft.com/en-us/library/windows.ui.xaml.controls.maps.mapcontrol.centerchanged.aspx ), but this does not provide any info about what caused the center change.
Is there any other way of knowing whether or not the user changed the map center?
/* To give some more context, my specific scenario is as follows:
Given an app which shows a map, I want to track the gps position of a user.
If a gps position is found, I want to put a dot on the map and center the map to that point.
If a gps position change is found, I want to center the map to that point.
If the user changes the position of the map by touch/swipe, I no longer want to center the map when the gps position changes.
I could hack this by comparing gps position and center, but he gps position latLng is a different type & precision as the Map.Center latLng. I'd prefer a simpler, less hacky solution.
*/
I solved this by setting a bool ignoreNextViewportChanges to true before calling the awaitable TrySetViewAsync and reset it to false after the async action is done.
In the event handler, I immediately break the Routine then ignoreNextViewportChanges still is true.
So in the end, it looks like:
bool ignoreNextViewportChanges;
public void HandleMapCenterChanged() {
Map.CenterChanged += (sender, args) => {
if(ignoreNextViewportChanges)
return;
//if you came here, the user has changed the location
//store this information somewhere and skip SetCenter next time
}
}
public async void SetCenter(BasicGeoposition center) {
ignoreNextViewportChanges = true;
await Map.TrySetViewAsync(new Geopoint(Center));
ignoreNextViewportChanges = false;
}
If you have the case that SetCenter might be called twice in parallel (so that the last call of SetCenter is not yet finished, but SetCenter is called again), you might need to use a counter:
int viewportChangesInProgressCounter;
public void HandleMapCenterChanged() {
Map.CenterChanged += (sender, args) => {
if(viewportChangesInProgressCounter > 0)
return;
//if you came here, the user has changed the location
//store this information somewhere and skip SetCenter next time
}
}
public async void SetCenter(BasicGeoposition center) {
viewportChangesInProgressCounter++;
await Map.TrySetViewAsync(new Geopoint(Center));
viewportChangesInProgressCounter--;
}
I'm working on a project for iOS using mvvmcross.
App navigation goes like this: first it starts from the splash screen (1), them it navigates to (2), a view to select between 3 options, in view (3) and (4) you get a list and also could navigate back to (2), if you select an item in (3) you navigate to (5) in a modal way.
Lastly, all navigation end up in (6), a view with an hamburger menu.
So I have traditional navigation(with back button), modal views and a hamburger menu at the end.
It would be great if someone could help me or guide me to see how to create a custom presenter for this navigation scheme.
I'm using MvxModalNavSupportTouchViewPresenter and a SlidingPanelsNavigationViewController, but don't know how to swap them when I navigate from (2,4,5) to (6)
A presenter is just something that implements https://github.com/MvvmCross/MvvmCross/blob/develop/MvvmCross/Core/Core/Views/IMvxViewPresenter.cs
public interface IMvxViewPresenter
{
void Show(MvxViewModelRequest request);
void ChangePresentation(MvxPresentationHint hint);
}
This is are really simple interface and it allows shared portable code like ViewModels to request changes in the display.
For the case where you want a Show request to change the entire UI from one display paradigm (modal navigation controller) to another (sliding panels), then one way to do this is to implement a presenter which has two child presenters and which simply switches them over.
In pseudo code this might look like:
public class MyPresenter : IMvxViewPresenter
{
private IMvxViewPresenter _currentPresenter;
private ModalPresenter _modalPresenter;
private SlidingPresenter _slidingPresenter;
private enum Style
{
Modal, Panels
}
private Style _currentStyle;
public MyPresenter()
{
// do whatever you need to do here to:
// - construct _modalPresenter and _slidingPresenter
// - make _modalPresenter attached to the window (via root view controller)
// - make _slidingPresenter hidden/unattached
_currentStyle = Style.Modal;
_currentPresenter = _modalPresenter;
}
public void Show(MvxViewModelRequest request)
{
if (_currentStyle == Style.Modal &&
request.ViewModelType == typeof(WhateverViewModelIndicatesTheSwitchIsNeeded))
{
DoSwitch(request);
return;
}
_currentPresenter.Show(request);
}
public void ChangePresentation(MvxPresentationHint hint)
{
_currentPresenter.ChangePresentation(hint);
}
private void DoSwitch(MvxViewModelRequest request)
{
// do whatever is necessary to:
// - remove _modalPresenter from the window
// - add _panelPresenter to the window
// - show `request` within _panelPresenter
_currentPresenter = _panelPresenter;
_currentStyle = Style.Panelsl
}
}
Obviously, there are some details to fill in within this pseudo-code - e.g. there are some viewcontrollers to be added and removed from the window - but this is just standard iOS manipulation - e.g. see lots of questions and answers like Changing root view controller of a iOS Window and Change rootViewController from uiviewcontroller to uinavigationcontroller
I am currently doing an application using Swing and i am stuck at a certain point. In my function, i have to link videos from a JList. The problem is i am not sure how to link the videos from the JList. I am using an OpenBrowser class to link the video to the internet. I did consider using JButton but i would have to hardcode it and that would be ugly. Is there any other alternatives to do this? I am in desperate need and would be eternally grateful to whoever that can help me.
Safa :)
If you don't want to open a browser with the video using a selection listener, you can consider the idea of launching it with a double click on a JList entry.
sample code
String[] items = {"i1", "i2", "i3", "i4"};
JList list = new JList(items);
list.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
JList list = (JList)evt.getSource();
if (evt.getClickCount() == 2) { //check if it is a Double-click
int index = list.locationToIndex(evt.getPoint());
// do whatever you want with the entry at that index
}
}
});
Desktp classes to browse some site (sample code):
if (desktop.isSupported(Desktop.Action.BROWSE)) {
URI uri = new URI("http://www.google.com");
desktop.browse(uri);
}
The desktop.browse() call will open your favourite browser with the given URL.