I have a button as part of a Xamarin Forms custom renderer. I can style the button as I wish on iOS and Android in code without an issue and for the most part, can do the same on Windows Phone 8.
I'm having a problem though with including an image on a button with text next to it and altering the border on the button so it is rounded. I've found plenty of examples using XAML, but not in pure C#.
Currently, the custom renderer on Windows Phone looks like this
[assembly: ExportRenderer(typeof(NewButton), typeof(NewButtonRenderer))]
namespace WinPhone
{
class NewButtonRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.ApplyTemplate();
var border = new Border
{
CornerRadius = new System.Windows.CornerRadius(10),
};
Control.Foreground = new SolidColorBrush(Colors.White);
Control.Background = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 130, 186, 132));
Control.BorderBrush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255,45,176,51)) ;
Control.BorderThickness = new System.Windows.Thickness(0.8);
}
}
}
}
I have a Border set up, but can't find a way to add it (and secondary to this, if I have the background, border brush and border thickness in the Border object, does it have the same effect as applying directly to the control?), nor a way of creating an image button with an image in my Images directory.
Is what I'm trying to do correct or am I missing a piece of the jigsaw? I'm doing this in pure C# for a specific reason.
Related
My app features a map, on which the user's avatar is displayed in the center and where markers including photo should be added when the user moves the map.
On the simulator, the markers are added but the images disappear as soon as I release the pointer then only the placeholders remain (this is what I call flickering). On the device, nothing is shown apart from the user's avatar.
As you can see the image does not remain on the map, only the placeholder does. The user icon is southern on the map but it is shown.
Please note: I am not receiving 404 errors and there is only one listener on the map (see below):
Here is how I trigger the map update:
googleMap.addMapListener((source, zoom, center) -> {
showReportsOnMap(googleMap, center, theme, currentForm, selectCategoryButton.getWidth());
});
And here is how I add the reports the map:
public void showReportsOnMap(
MapContainer currentMap,
Coord center,
Resources theme,
Form f,
int reportImageWidth) {
/**
* Get the map borders (CAUTION : it can be NaN)
*/
Coord NE = currentMap.getCoordAtPosition(currentMap.getAbsoluteX() + currentMap.getWidth(), currentMap.getAbsoluteY());
Coord SW = currentMap.getCoordAtPosition(currentMap.getAbsoluteX(), currentMap.getAbsoluteY() + currentMap.getHeight());
boolean bordersKnownAndValid = false;
// Checks that the borders does not contain NaN as longitudes and latitudes
if (!Double.isNaN(NE.getLatitude())
&& !Double.isNaN(NE.getLongitude())
&& !Double.isNaN(SW.getLatitude())
&& !Double.isNaN(SW.getLongitude())) {
// The borders can be used
bordersKnownAndValid = true;
}
if (bordersKnownAndValid) {
ArrayList<Report> localReports = (ArrayList<Report>) (Report.getReportsWithinBoundingBounds(NE, SW, selectedCategoryIdToBeShownOnMap).get(1));
// Revalidate only if we have something new to show
if (localReports.size() > 0) {
currentMap.clearMapLayers();
currentMap.addMarker(ParametresGeneraux.getCurrentUser().getUserIcon(),
new Coord(ParametresGeneraux.getCurrentUser().getCurrentUserLocation().getLatitude(),
ParametresGeneraux.getCurrentUser().getCurrentUserLocation().getLongitude()),
ParametresGeneraux.getCurrentUser().getUserNickname(), "", null);
Image tempPlaceholder = Image.createImage(
reportImageWidth,
reportImageWidth,
ParametresGeneraux.accentColor);
Graphics gr = tempPlaceholder.getGraphics();
gr.setAntiAliased(true);
gr.setColor(ParametresGeneraux.accentColor);
gr.fillArc(0, 0, reportImageWidth, reportImageWidth, 0, 360);
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
// Add the report on the map
for (Report report : localReports) {
String photoFilenameInStorage = Report.getFilename(report.getPhotoPath())
+ ParametresGeneraux.SUFFIX_ON_MAP_IMAGE;
EncodedImage reportIcon = EncodedImage.createFromImage(URLImage.createToStorage(roundPlaceholder,
photoFilenameInStorage,
report.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
),
false); // we want transparency png otherwise it shows black edges
currentMap.addMarker(reportIcon,
new Coord(report.getLocation().getLatitude(), report.getLocation().getLongitude()
),
report.getCategory().getName(), "",
(evt) -> {
// Opens the detail form about this report
new ReportDetailsForm(theme, report, f.getClass()).show();
});
}
currentMap.setCameraPosition(new Coord(center.getLatitude(), center.getLongitude()));
currentMap.zoom(new Coord(center.getLatitude(),
center.getLongitude()),
ParametresGeneraux.getUserZoomLevelOnMap());
currentMap.animate();
//f.forceRevalidate();
}
}
}
So I guess that the flickering in the simulator is a kind of slow motion of what happens on the device although the device does not show the placeholder.
What should I do to make the markers appear with an image?
EDIT March 8th 2017
On simulator, if I show a Dialog just before adding the marker to the map with this code :
Dialog.show("Photo", report.getAddress(), Dialog.TYPE_INFO, reportIcon, "OK", null);
The icon is well displayed in the Dialog (see screen capture below)
and then the image appears on the map without flickering any more as depicted below :
However on an actual Android device even the Dialog does not appear.
Finally I don't know why the Dialog makes then the markers behave as expected on the simulator but not on the device, so I am a bit at lost!
Any help would be precious.
The problem is that URLImage may not have finished downloading by the time you added it as a marker. If you call EncodedImage.createFromImage(urlImage) before URLImage has finished downloading, then you'll be creating an encoded image of the urlImage's placeholder.
the com.codename1.io.Util class includes quite a few methods for downloading images from URLs. Some are blocking, and some use a callback. Either way you just need to ensure that the image is actually downloaded before adding it to a map.
NOTE: Normally this wouldn't be an issue with URLImage - e.g. if you were adding it to a Button or a Label. It is only a problem here because the MapContainer is native, and it actually needs to pass the image data to the native layer at the time that setMarker() is called.
I'm making app with using Xamarin.forms.
You all know regular tabs for Android from Xamarin.forms' TabbedPage is at top.
Because it should be there if it's Native Android app that respect Android UX.
But things are changed now.
Even Google announced new bottom tab bar called "bottom Navigation".
https://github.com/roughike/BottomBar
Many major apps're using bottom tab bar.
But I can't use new Bottom Navigation.
Because my app is base on Xamarin.forms and uses TabbedPage from forms.
It's going to be more complicated if I try to use bottom Navigation.
(I'm making iOS app from forms too)
So Best approach would be moving native Tabs to bottom.
So I found this. (maybe old)
http://envyandroid.com/align-tabhost-at-bottom/
But don't know how to use in Xamarin.Android.
Could you help me?
Had ran the same issue, tried to create a custom TabbedPageRenderer from the code present at GitHub but no luck due to several classes and interfaces scoped as internal. Found a solution, a hacky one though, but seems to work fine in our case.
Simply created a new BottomTabbedPage inheriting from TabbedPage so you can link a new Renderer for Android, then create a new Renderer as follows:
[assembly: ExportRenderer(typeof(BottomTabbedPage), typeof(BottomTabbedPageRenderer))]
namespace My.XForms.Droid.Renderers
{
public class BottomTabbedPageRenderer : TabbedPageRenderer
{
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
InvertLayoutThroughScale();
base.OnLayout(changed, l, t, r, b);
}
private void InvertLayoutThroughScale()
{
ViewGroup.ScaleY = -1;
TabLayout tabLayout = null;
ViewPager viewPager = null;
for (int i = 0; i < ChildCount; ++i)
{
Android.Views.View view = (Android.Views.View)GetChildAt(i);
if (view is TabLayout) tabLayout = (TabLayout)view;
else if (view is ViewPager) viewPager = (ViewPager)view;
}
tabLayout.ScaleY = viewPager.ScaleY = -1;
viewPager.SetPadding(0, -tabLayout.MeasuredHeight, 0, 0);
}
}
}
Just scaling the page layout and then scaling the children again doesn't make the trick because the original TabbedPageRenderer pads the ViewPager to not to overlap with the TabLayout, so your contained pages would appear with a starting gap so inserting the negative padding fixes that.
Not an ideal solution, just works, but at least you don't run through a full TabbedPage implementation.
Use BottomNavigationBarXF NuGet package for Xamarin Forms.
The result:
I'm using the new toolbar widget introduced in the appcompat / support-v7. I would like to hide/show the toolbar depending on if the user is scrolling up/down the page, just like in the new Google's playstore app or NewsStand app. Is there something built into the toolbar widget for this or should I be using it in conjunction with FrameLayout and ObservableScrollView?
As far as I know there is nothing build in that does this for you. However you could have a look at the Google IO sourcecode, especially the BaseActivity. Search for "auto hide" or look at onMainContentScrolled
In order to hide the Toolbar your can just do something like this:
toolbar.animate().translationY(-toolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).start();
If you want to show it again you call:
toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator()).start();
For hiding the toolbar you can just do :
getSupportActionBar().hide();
So you just have to had a scroll listener and hide the toolbar when the user scroll !
Hide:
getSupportActionBar().hide();
Show:
getSupportActionBar().show();
The answer is straightforward. Just implement OnScrollListenerand hide/show your toolbar in the listener. For example, if you have listview/recyclerview/gridview, then follow the example.
In your MainActivity Oncreate method, initialize the toolbar.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
}
And then implement the OnScrollListener
public RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
boolean hideToolBar = false;
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (hideToolBar) {
((ActionBarActivity)getActivity()).getSupportActionBar().hide();
} else {
((ActionBarActivity)getActivity()).getSupportActionBar().show();
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 20) {
hideToolBar = true;
} else if (dy < -5) {
hideToolBar = false;
}
}
};
I got the idea from: https://stackoverflow.com/a/27063901/1079773
Android Design Support Library can be used to show/hide toolbar.
See this.
http://android-developers.blogspot.kr/2015/05/android-design-support-library.html
And there are detail samples here.
http://inthecheesefactory.com/blog/android-design-support-library-codelab/en
There are actually quite a number of ways to hide/show the toolbar while you are scrolling the content. One of the ways is to do it via the Android Design Support Library or more specifically the Coordinator layout aka. super-powered frame layout.
Basically all you need to do is to have the following structure in your layout file and you should be able to achieve the result that you want.
<CoordinatorLayout>
<AppBarLayout>
</AppBarLayout>
<NestedScrollView>
</NestedScrollView>
</CoordinatorLayout>
I have actually made a video to explain how it can be done in a step by step manner. Feel free to check it out and let me know if it helps. Thanks! :)
https://youtu.be/mEGEVeZK7Nw
Just add this property inside your toolbar and its done
app:layout_scrollFlags="scroll|enterAlways"
Isn't is awesome
I've been trying to implement the same behavior, here is the brunt of code showing and hiding the toolbar (put in whatever class containing your RecyclerView):
int toolbarMarginOffset = 0
private int dp(int inPixels){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, inPixels, getApplicationContext().getResources().getDisplayMetrics());
}
public RecyclerView.OnScrollListener onScrollListenerToolbarHide = new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
toolbarMarginOffset += dy;
if(toolbarMarginOffset>dp(48)){
toolbarMarginOffset = dp(48);
}
if(toolbarMarginOffset<0){
toolbarMarginOffset = 0;
}
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)toolbar.getLayoutParams();
params.topMargin = -1*toolbarMarginOffset;
toolbar.setLayoutParams(params);
}
};
I've included the dp function to convert from pixels to dp but obviously set it to whatever your toolbar height is. (replace dp(48) with your toolbar height)
Where-ever you setup your RecyclerView include this:
yourListView.setOnScrollListener(onScrollListenerToolbarHide);
However, there are a couple additional issues if you are also using a SwipeRefreshLayout.
I've had to set the marginTop of the first element in the adapter for the RecyclerView to the Toolbar's height plus original offset. (A bit of a hack I know). The reason for this is I found that if I changed my above code to include changing the marginTop of the recyclerView while scrolling it was a jittery experience. So that's how I overcame it. So basically setup your layout so that your toolbar is floating on top of the RecyclerView (clipping it) Something like this (in onBindViewHolder of your custom RecyclerView adapter) :
if(position==0){
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)holder.card.getLayoutParams();
// params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
params.topMargin = dp(10+48);
}
And lastly, since there is a large offset the RecyclerViews refresh circle will be clipped, so you'll need to offset it (back in onCreate of your class holding your RecyclerView):
swipeLayout.setProgressViewOffset(true,dp(48),dp(96));
I hope this helps someone. Its my first detailed answer so I hope I was detailed enough.
To hide the menu for a particular fragment:
setHasOptionsMenu(true); //Inside of onCreate in FRAGMENT:
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.action_search).setVisible(false);
}
I implemented a utility class to do the whole hide/show Toolbar animation when scrolling. You can see the article here http://rylexr.tinbytes.com/2015/04/27/how-to-hideshow-android-toolbar-when-scrolling-google-play-musics-behavior/. Source code is here https://github.com/rylexr/android-show-hide-toolbar.
A library and demo with the complete source code for scrolling toolbars or any type of header can be downloaded here:
https://github.com/JohannBlake/JBHeaderScroll
Headers can be Toolbars, LinearLayouts, RelativeLayouts, or whatever type of view you use to create a header.
The scrollable area can be any type of scroll content including ListView, ScrollView, WebView, RecyclerView, RelativeLayout, LinearLayout or whatever you want.
There's even support for nested headers.
It is indeed a complex undertaking to synchronize headers (toolbars) and scrollable content the way it's done in Google Newsstand.
This library doesn't require implementing any kind of onScrollListener.
The solutions listed above by others are only half baked solutions that don't take into consideration that the top edge of the scrollable content area beneath the toolbar has to initially be aligned to the bottom edge of the toolbar and then during scrolling the content area needs to be repositioned and possibly resized. The JBHeaderScroll handles all these issues.
There is an Android library called Android Design Support Library that's a handy library where you can find of all of those Material fancy design things that the Material documentation presents without telling you how to do them.
It's well presented in this Android Blog post. The "Collapsing Toolbar" in particular is what you're looking for.
I need the ability to be able to create an image of size 400x400 on the fly in a Windows Phone app, which will have a color of ARGB values that a user selects from a color picker. For instance, the user will click on a HyperlinkButton to take them to a ColorPickerPage and then will select a color, and I will retrieve that value and create the image from it, and display this image back on the MainPage. How might something like this be accomplished one I have retrieved the ARGB value from the user? I have not had luck finding any resources on this particular issue.
EDIT**
I came across http://www.geekchamp.com/forums/windows-phone-development/how-to-correctly-save-uicontrol-with-opacity-to-writeablebitmap which creates a rectangle on the screen and then saves to WriteableBitmap, but how might I skip that step and just save the Rectangle to WriteableBitmap? Note, I only have a single rectangle that I Fill with a custom Color.
You can save any UI element as an image using the code below. Here rect is the name of the rectangle in your XAML. If the rectangle isn't present in the UI then simply create one using C#. I have added the code to create a rectangle using C# and commented it.
public void saveimage(int height, int width, String filename)
{
//Rectangle rect = new Rectangle();
//rect.Height = 40;
//rect.Width = 40;
//rect.Fill = new SolidColorBrush(System.Windows.Media.Colors.Cyan);
var bmp = new WriteableBitmap(width, height);
bmp.Render(rect, null);
bmp.Invalidate();
var isf = IsolatedStorageFile.GetUserStoreForApplication();
if (!isf.FileExists(filename))
{
using (var stream = isf.OpenFile(filename, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite))
{
bmp.SaveJpeg(stream, width, height, 0, 100);
stream.Close();
}
}
}
Did you try using the Drawing Class.
here's the reference from msdn.
These are some samples: System.Drawing and System.Drawing.Imaging alternatives for Windows Phone
http://code.msdn.microsoft.com/windowsapps/Multi-Touch-Drawing-744a0b48
Hope it helps!
I saw a site that implements a TextPrompt.
http://tips4java.wordpress.com/2009/11/29/text-prompt/
In the implementation, there is a setShow(Show.ALWAYS) method to always show the prompt text whether a JTextField has focus or not.
JTextField tf = new JTextField();
TextPrompt tp = new TextPrompt("Prompt", tf);
tp.setShow(Show.ALWAYS);
Is there a way to do it in JavaFX?
The way is to override the default css style of pseudo class "focused" of textfield. To do that load your own css file with this
.text-field:focused {
-fx-background-color: -fx-focus-color, -fx-text-box-border, -fx-control-inner-background;
-fx-background-insets: -0.4, 1, 2;
-fx-background-radius: 3.4, 2, 2;
-fx-prompt-text-fill: transparent; /* <----- Remove this line */
}
content and remove the -fx-prompt-text-fill attribute from it.
CSS loading example https://stackoverflow.com/a/9739698.