I have an imageview on which I have set a bitmap fetched from an url.
On the imageview I have set an onClickListener which opens up a dialog.
I want to somehow change the tint (make it darker) when the imageview is pressed upon to provide a sort of button click like feel.
What do you suggest?
happydude's answer is the most elegant way to handle this but unfortunately (as pointed out in the comments) the source code for ImageView only accepts an integer (solid colour). Issue 18220 has been around for a couple years addressing this, I've posted a workaround there that I'll summarize here:
Extend ImageView and wrap drawableStateChanged() with code that sets the tint based on the new state:
TintableImageView.java
package com.example.widgets;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.support.v7.widget.AppCompatImageView;
import com.example.R;
public class TintableImageView extends AppCompatImageView {
private ColorStateList tint;
public TintableImageView(Context context) {
super(context);
}
public TintableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public TintableImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TintableImageView, defStyle, 0);
tint = a.getColorStateList(R.styleable.TintableImageView_tintColorStateList);
a.recycle();
}
#Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (tint != null && tint.isStateful())
updateTintColor();
}
private void updateTintColor() {
int color = tint.getColorForState(getDrawableState(), 0);
setColorFilter(color);
}
}
Define a custom attribute:
attrs.xml
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<declare-styleable name="TintableImageView">
<attr name="tintColorStateList" format="reference|color" />
</declare-styleable>
</resources>
Use the widget and custom attribute with your local namespace instead of Android's:
example_layout.xml
<?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="match_parent"
android:orientation="horizontal">
<com.example.widgets.TintableImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/example"
android:clickable="true"
app:tintColorStateList="#color/color_selector"/>
</LinearLayout>
You can then use a colour selector like happydude suggested:
color_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="#color/pressed_color"/>
<item android:color="#00000000"/>
</selector>
One way would be to use a combination of a ColorFilter and a ColorStateList that contains your tint color for when the button is pressed. The xml for the ColorStateList in the res/color directory would look like this:
button_pressed.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="#color/pressed_color"/>
<item android:color="#00000000"/>
</selector>
where #color/pressed_color is your tint color (which should be partially transparent). Then in your ImageView subclass, you apply the color by overriding drawableStateChanged().
#Override
protected void drawableStateChanged() {
super.drawableStateChanged();
ColorStateList list = getResources().getColorStateList(R.color.button_pressed);
int color = list.getColorForState(getDrawableState(), Color.TRANSPARENT);
setColorFilter(color);
invalidate();
}
Any time the button's state changes, this code is called and will automatically set the tint as appropriate.
I'd have to test it out, but you should be able to set an xml with that behaviour as the ImageView drawable, and then set your bitmap as the ImageView background.
For me a simple solution is working, using setAlpha(180) in onClick event make the image darker, giving the user a feedback that it was clicked or touched.
final ImageView myImage = (ImageView) findViewById(R.id.ivDocument);
myImage.setImage...(... your image ...); // load your ImageView
myImage.setClickable(true);
myImage.setFocusable(true);
myImage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
myImage.setAlpha(180);
doWhateverYouWantHere(v);
}
});
Regarding your XML layout, nothing special.
This code snippet worked for me:
porterDuffColorFilter = newPorterDuffColorFilter(getResources().getColor(R.color.cardview_dark_background),PorterDuff.Mode.MULTIPLY);
imgView.getDrawable().setColorFilter(porterDuffColorFilter);
imgView.setBackgroundColor(Color.TRANSPARENT);
Related
I am new to Xamarin.Forms and XAML. I am trying to get tab icons to display for ONLY IOS for the my different pages in my TabbedPage. I did a bit of search and I have come to know that UIKit has a reference to system icons available on IOS at UITabBarSystem. How can I make use of the elements in that enum without having to get those icons from the internet? The TabbedPage is the root with children pages that are ContentPages and ListView pages. So as you will see from the attached sample, I would like the "IconImageSource" property for FavouritesPage to get the image from the iOS UIKit. Is that possible?
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:PhoneApp.Views"
x:Class="PhoneApp.Views.MainPage">
<TabbedPage.Title>
</TabbedPage.Title>
<TabbedPage.Children>
<views:FavouritesPage Title="Favourites" IconImageSource=""/>
<views:RecentsPage Title="Recents"/>
<views:ContactsPage Title="Contacts"/>
<views:KeypadPage Title="Keypad"/>
<views:VoicemailPage Title="Voicemail"/>
</TabbedPage.Children>
</TabbedPage>
I think I found the right solution for you. If you want to use native Api's on Xamarin controls, you can use custom renderer for them which are great! Here is the renderer for the TabedPage:
[assembly: ExportRenderer(typeof(MainPage), typeof(MyTabbedPageRenderer))]
namespace TestApp.iOS
{
public class MyTabbedPageRenderer : TabbedRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (TabBar?.Items == null) return;
//Setting the Icons
TabBar.Items[0].Image = GetTabIcon(UITabBarSystemItem.Search);
TabBar.Items[1].Image = GetTabIcon(UITabBarSystemItem.Downloads);
TabBar.Items[2].Image = GetTabIcon(UITabBarSystemItem.Bookmarks);
}
private UIImage GetTabIcon(UITabBarSystemItem systemItem)
{
//Convert UITabBarItem to UIImage
UITabBarItem item = new UITabBarItem(systemItem, 0);
return UIImage.FromImage(item.SelectedImage.CGImage, item.SelectedImage.CurrentScale, item.SelectedImage.Orientation);
}
}
}
I created a sample for you, which you can find here. If you have any questions, please ask!
Regards
I am fairly new to all of this and am currently attempting to get the height of the tabs in the Xamarin tabbed page form. The only solution I found to this is to write a custom renderer, and that is what I'm having a hard time with.
After a couple days of struggling I managed to get to this spot (hopefully on the right track), however I just cannot understand how to connect the XAML to my custom tabbed page. This is what I have so far.
GameTab.xaml
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Diplomacy.Views.GameTab"
xmlns:pages="clr-namespace:Diplomacy.Views"
xmlns:custom="clr-namespace:Diplomacy.CustomRenderers">
<!--Pages can be added as references or inline-->
<TabbedPage.Children>
<pages:TabbedMap Title="Map" Icon="tank.png"/>
<pages:TabbedChat Title="Chat" Icon="chat.png"/>
</TabbedPage.Children>
</TabbedPage>
GameTab.xaml.cs
namespace Diplomacy.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class GameTab : Xamarin.Forms.TabbedPage
{
SelectionGamesViewModel viewModel;
public GameTab(SelectionGamesViewModel viewModel)
{
InitializeComponent();
// Disables switching between tabs with the swipe gesture
On<Xamarin.Forms.PlatformConfiguration.Android>().DisableSwipePaging();
// Sets the tab at the bottom in android phones
On<Xamarin.Forms.PlatformConfiguration.Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);
BindingContext = this.viewModel = viewModel;
}
}
MyCustomRenderer.cs
namespace Diplomacy.CustomRenderers
{
public class CustomTabbedPage : Xamarin.Forms.TabbedPage
{
}
}
At this point my next step is to use the CustomTabbedPage (correct me if I'm wrong from here on out).
With this line: xmlns:custom="clr-namespace:Diplomacy.CustomRenderers"
I should be able to wedge myself into the Xamarin Tabbed Page form with my custom render, which currently does nothing.
The way that I believe this is done is by changing TabbedPage to CustomTabbedPage like shown below
<?xml version="1.0" encoding="utf-8" ?>
<custom:CustomTabbedPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Diplomacy.Views.GameTab"
xmlns:pages="clr-namespace:Diplomacy.Views"
xmlns:custom="clr-namespace:Diplomacy.CustomRenderers">
<!--Pages can be added as references or inline-->
.
. // Same stuff goes here
.
</custom:CustomTabbedPage>
However when I do that, I get all sorts of errors in GameTab.xaml.cs and 1 error in the navigation page trying to push GameTab (the 2nd error)
I've been struggling probably for weeks now, I really need some help on how to set up this custom render. I get the theory of what it does and what is it's purpose, however I don't fully understand how the compiler handles it all, and how to link it all together. Please and thank you. Sorry for the long question, I just wanted to be thorough.
EDIT:
This is the Android custom renderer code that lives in Diplomacy.Android
[assembly: ExportRenderer(typeof(CustomTabbedPage), typeof(MyTabbedPage))]
namespace Diplomacy.Droid.CustomRenderer
{
public class MyTabbedPage : TabbedRenderer
{
public MyTabbedPage(Context context) : base(context)
{
}
}
}
All the errors that you get are for one and one reason alone that the other part of your partial class i.e. GameTab.xaml.cs files GameTab class is not inheriting from your CustomTabbedPage but your Xamarin.Forms.TabbedPage
All you have to do is something like this in your GameTab.xaml.cs
public partial class GameTab : Diplomacy.CustomRenderers.CustomTabbedPage
I am getting all sorts of weird errors trying to instantiate a popup page in Xaml. This is the most vexing:
No property, bindable property, or event found for 'Content', or mismatching type between value and property.
Here's the page presenting the popup:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns ="http://xamarin.com/schemas/2014/forms"
xmlns:x ="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class ="PopupPages.PopupBackingPage"
xmlns:popup ="clr-namespace:PopupPages"
BackgroundColor="Transparent">
<popup:PopupTest />
</ContentPage>
Here's its code-behind:
namespace PopupPages
{
public partial class PopupBackingPage : ContentPage
{
public PopupBackingPage()
{
InitializeComponent();
}
}
}
Here's the popup page itself, in xaml:
<?xml version="1.0" encoding="utf-8" ?>
<pages:PopupPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
xmlns:animations="clr-namespace:Rg.Plugins.Popup.Animations;assembly=Rg.Plugins.Popup"
x:Class="PopupPages.PopupTest">
</pages:PopupPage>
And here's the code-behind for the popup page itself:
namespace PopupPages
{
public partial class PopupTest : Rg.Plugins.Popup.Pages.PopupPage
{
public PopupTest()
{
InitializeComponent();
}
}
}
What's going on? What am I doing wrong? These are as dead simple as can be.
A Rg.Plugins.Popup is a page itself and can't be shown in a ContentPage. When wanting to display a popup page, display them using code like below:
await PopupNavigation.Instance.PushAsync(new PopupTest());
Put this code in the event that you were going to show the PopupBackingPage. A backing page is not needed and won't work with the Rg.Plugins.Popup pages.
Hopefully this helps!
Xamarin forms Android how We change Tabbed Page Icon Size. I have Using AppCompact Themes and I want Increase Tabbed Page icon size in Tabbar.axaml
You can create a Custom renderer and change the size of icon in the native platform. Actually you can override the whole tab's layout.
For example, in PCL first create a class inherit from TabbedPage:
public class MyTabbedPage : TabbedPage
{
}
Then create its renderer in Android project for example like this:
[assembly: ExportRenderer(typeof(MyTabbedPage), typeof(MyTabbedPageRenderer))]
namespace YourNameSpace.Droid
{
public class MyTabbedPageRenderer : TabbedPageRenderer
{
protected override void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
{
base.SetTabIcon(tab, icon);
tab.SetCustomView(Resource.Layout.mytablayout);
var imageview = tab.CustomView.FindViewById<ImageView>(Resource.Id.icon);
imageview.SetBackgroundDrawable(tab.Icon);
}
}
}
The layout I created is like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="fitCenter"
android:id="#+id/icon"
android:layout_gravity="center_horizontal" />
</LinearLayout>
As you can see, I set the size directly in the axml file.
When you want to use this custom TabbedPage, you can for example code like this:
<local:MyTabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabbedPageForms"
x:Class="TabbedPageForms.MainPage">
<local:TodayPage Title="Today" Icon="hamburger.jpg" />
<local:SchedulePage Title="Schedule" Icon="hamburger.jpg" />
</local:MyTabbedPage>
Code behind:
public partial class MainPage : MyTabbedPage
{
public MainPage()
{
InitializeComponent();
}
}
I have some ImageView's:
The selector for right arrow button is:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="3" android:state_pressed="true"/> <!-- pressed -->
<item android:drawable="1" android:state_enabled="false"/> <!-- enabled -->
<item android:drawable="2"/> <!-- default -->
</selector>
(1, 2, 3 look like the ones in the picture below — 1 is for left arrow button, but the right's one looks like the same with opposite direction).
Now my problem is:
When the user does click, I use setEnable() to change its status. It works.
When the user does long click, again, I use setEnable() to change its status. But after the user released his finger, the button retains status as image #3.
I tried: cancelLongPress(), clearFocus(), invalidate(), post(Runnable), postInvalidate(), refreshDrawableState()… but they didn't work.
The app uses minimum SDK 4 (Android 1.6). Could you help me?
Thanks,
Temporary solution:
...
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
v.postDelayed(new Runnable() {
#Override
public void run() {
v.setEnabled(...);
}// run()
}, 200); // 200 ms is enough
}
return false;
}// onTouch()
});