maui-linux/Xamarin.Forms.Platform.Android/CellAdapter.cs

339 строки
8.8 KiB
C#
Исходник Обычный вид История

2016-03-22 23:02:25 +03:00
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using Android.App;
using Android.Content;
using Android.Util;
using Android.Views;
using Android.Widget;
using AView = Android.Views.View;
using AListView = Android.Widget.ListView;
using Android.Graphics.Drawables;
[All] Page embedding (#1124) * Fix broken SetTextAppearance call when targeting below API 23 * Enable embedding XF apps in Android * VS didn't save the project file * Allow retrieving rendered XF VisualElements for use in UWP apps * Prevent XF from slaughtering the menu bar in embedded scenarios * ? * Post-rebase fixups * Create embedding test project for Android * Create iOS test bed project * Attempting to get functional embedded project * Android and iOS functional testbed projects * Basic embedding app on UWP * First pass at handling navigation to Forms page from UWP * Fleshed out example, added parameter checks, sealed wrapper class * Create test page and load it from UWP * Make DisplayAlert/DisplayActionSheet independent of Platform instance on UWP * Set up test page for alerts/actionsheets on Android * Move DisplayAlert/ActionSheet code to a helper class so embedded Forms can use it * VS didn't save my changes * Add test page for alerts and action sheets * Get FrameworkElement from renderer * Page -> ContentPage * Can now display the webview embedded page * Example working on iOS * Repro of crash * Remove the IStartActivityForResult dependency from FormsWebChromeClient * Created repro * Remove need for Forms.Context to create renderers * Remove Forms.Context dependencies in ScrollViewRenderer * Remove Forms.Context dependencies in FrameRenderer * Remove Forms.Context dependencies * Remove Context/Forms.Context dependencies in Drawable subclasses * Remove some more Forms.Context dependencies * CellAdapter no longer dependent on Forms.Context * Obsolete ToAndroid using Forms.Context * Remove Forms.Context dependencies in ResourceManager * Remove need for Forms.Context for SupportsProgress * Remove Forms.Context dependency for setting titlebar visibility * Remove Forms.Context dependencies in GetAccentColor * Some comments about caching * Remove Forms.Context dependencies for AndroidPlatformServices and ResourceProvider * Remove Forms.Context dependencies in Maps * Disabled warnings for Forms.Context in CustomRenderers * Filter logs so we don't get those annoying "parked" messages * Filter alerts/actionsheets/activityindicator by context * Clean up constructor debugging messages * Remove old TODOs * Set up test page for Device.Openuri * Make AndroidDeviceInfo more resilient to multiple activity scenarios * Use parameter instead of member * Add missing parameterless constructors for embedded fragment wrappers * Fix multiple popup subscriptions for embedded context * Remove UpdateGlobalContext and Page Context attached property * Obsolete static reference to Context * Warnings as errors in embedded test bed projects * Comment cleanup * Clean up unused code * Obsolete old constructor for DefaultRenderer * Make sure embedded fragment wrappers handle disposing the platform * Revert to old DependencyService registration for ResourceProvider; use ApplicationContext for ResourceProvider; Comments for everything happing in Forms.SetupInit * Remove old TODO * Make PopupManager take the correct type instead of casting a bunch * Update docs * Add missing nuspec entry for FormsEmbeddedPageWrapper * Post-rebase cleanup * Update docs * Disable XF target validation so package restore works * Restore InputTransparent handling lost in rebase * Restore parameter lost during rebase * Finalize the list of subscriptions to avoid 'modified collection' errors * Avoid double-fetching Context * Fix "with you package" typo
2017-10-09 20:51:55 +03:00
using Android.Support.V7.App;
2016-03-22 23:02:25 +03:00
namespace Xamarin.Forms.Platform.Android
{
public abstract class CellAdapter : BaseAdapter<object>, AdapterView.IOnItemLongClickListener, ActionMode.ICallback, AdapterView.IOnItemClickListener,
global::Android.Support.V7.View.ActionMode.ICallback
{
readonly Context _context;
ActionMode _actionMode;
Cell _actionModeContext;
bool _actionModeNeedsUpdates;
AView _contextView;
global::Android.Support.V7.View.ActionMode _supportActionMode;
protected CellAdapter(Context context)
{
if (context == null)
throw new ArgumentNullException("context");
_context = context;
}
internal Cell ActionModeContext
{
get { return _actionModeContext; }
set
{
if (_actionModeContext == value)
return;
if (_actionModeContext != null)
((INotifyCollectionChanged)_actionModeContext.ContextActions).CollectionChanged -= OnContextItemsChanged;
ActionModeObject = null;
_actionModeContext = value;
if (_actionModeContext != null)
{
((INotifyCollectionChanged)_actionModeContext.ContextActions).CollectionChanged += OnContextItemsChanged;
ActionModeObject = _actionModeContext.BindingContext;
}
}
}
internal object ActionModeObject { get; set; }
internal AView ContextView
{
get { return _contextView; }
set
{
if (_contextView == value)
return;
if (_contextView != null)
{
var isSelected = (bool)ActionModeContext.GetValue(ListViewAdapter.IsSelectedProperty);
if (isSelected)
SetSelectedBackground(_contextView);
else
UnsetSelectedBackground(_contextView);
}
_contextView = value;
if (_contextView != null)
SetSelectedBackground(_contextView, true);
}
}
public bool OnActionItemClicked(ActionMode mode, IMenuItem item)
{
mode.Menu.Clear();
2016-03-22 23:02:25 +03:00
OnActionItemClickedImpl(item);
_actionMode?.Finish();
2016-03-22 23:02:25 +03:00
return true;
}
bool global::Android.Support.V7.View.ActionMode.ICallback.OnActionItemClicked(global::Android.Support.V7.View.ActionMode mode, IMenuItem item)
{
mode.Menu.Clear();
2016-03-22 23:02:25 +03:00
OnActionItemClickedImpl(item);
_supportActionMode?.Finish();
2016-03-22 23:02:25 +03:00
return true;
}
public bool OnCreateActionMode(ActionMode mode, IMenu menu)
{
CreateContextMenu(menu);
return true;
}
bool global::Android.Support.V7.View.ActionMode.ICallback.OnCreateActionMode(global::Android.Support.V7.View.ActionMode mode, IMenu menu)
{
CreateContextMenu(menu);
return true;
}
public void OnDestroyActionMode(ActionMode mode)
{
OnDestroyActionModeImpl();
_actionMode.Dispose();
_actionMode = null;
}
void global::Android.Support.V7.View.ActionMode.ICallback.OnDestroyActionMode(global::Android.Support.V7.View.ActionMode mode)
{
OnDestroyActionModeImpl();
_supportActionMode.Dispose();
_supportActionMode = null;
}
public bool OnPrepareActionMode(ActionMode mode, IMenu menu)
{
return OnPrepareActionModeImpl(menu);
}
bool global::Android.Support.V7.View.ActionMode.ICallback.OnPrepareActionMode(global::Android.Support.V7.View.ActionMode mode, IMenu menu)
{
return OnPrepareActionModeImpl(menu);
}
public void OnItemClick(AdapterView parent, AView view, int position, long id)
{
if (_actionMode != null || _supportActionMode != null)
{
var listView = parent as AListView;
if (listView != null)
position -= listView.HeaderViewsCount;
HandleContextMode(view, position);
}
else
HandleItemClick(parent, view, position, id);
}
public bool OnItemLongClick(AdapterView parent, AView view, int position, long id)
{
var listView = parent as AListView;
if (listView != null)
position -= listView.HeaderViewsCount;
return HandleContextMode(view, position);
}
protected abstract Cell GetCellForPosition(int position);
protected virtual void HandleItemClick(AdapterView parent, AView view, int position, long id)
{
}
protected void SetSelectedBackground(AView view, bool isContextTarget = false)
{
int attribute = isContextTarget ? global::Android.Resource.Attribute.ColorLongPressedHighlight : global::Android.Resource.Attribute.ColorActivatedHighlight;
2016-03-25 23:53:19 +03:00
using (var value = new TypedValue())
2016-03-22 23:02:25 +03:00
{
if (_context.Theme.ResolveAttribute(attribute, value, true))
view.SetBackgroundResource(value.ResourceId);
else
view.SetBackgroundResource(global::Android.Resource.Color.HoloBlueDark);
}
}
protected void UnsetSelectedBackground(AView view)
{
view.SetBackgroundResource(0);
}
internal void CloseContextActions()
2016-03-22 23:02:25 +03:00
{
_actionMode?.Finish();
_supportActionMode?.Finish();
2016-03-22 23:02:25 +03:00
}
void CreateContextMenu(IMenu menu)
{
var changed = new PropertyChangedEventHandler(OnContextActionPropertyChanged);
var changing = new PropertyChangingEventHandler(OnContextActionPropertyChanging);
var commandChanged = new EventHandler(OnContextActionCommandCanExecuteChanged);
for (var i = 0; i < ActionModeContext.ContextActions.Count; i++)
{
MenuItem action = ActionModeContext.ContextActions[i];
IMenuItem item = menu.Add(global::Android.Views.Menu.None, i,global::Android.Views.Menu.None, action.Text);
var icon = action.Icon;
if (icon != null)
{
[All] Page embedding (#1124) * Fix broken SetTextAppearance call when targeting below API 23 * Enable embedding XF apps in Android * VS didn't save the project file * Allow retrieving rendered XF VisualElements for use in UWP apps * Prevent XF from slaughtering the menu bar in embedded scenarios * ? * Post-rebase fixups * Create embedding test project for Android * Create iOS test bed project * Attempting to get functional embedded project * Android and iOS functional testbed projects * Basic embedding app on UWP * First pass at handling navigation to Forms page from UWP * Fleshed out example, added parameter checks, sealed wrapper class * Create test page and load it from UWP * Make DisplayAlert/DisplayActionSheet independent of Platform instance on UWP * Set up test page for alerts/actionsheets on Android * Move DisplayAlert/ActionSheet code to a helper class so embedded Forms can use it * VS didn't save my changes * Add test page for alerts and action sheets * Get FrameworkElement from renderer * Page -> ContentPage * Can now display the webview embedded page * Example working on iOS * Repro of crash * Remove the IStartActivityForResult dependency from FormsWebChromeClient * Created repro * Remove need for Forms.Context to create renderers * Remove Forms.Context dependencies in ScrollViewRenderer * Remove Forms.Context dependencies in FrameRenderer * Remove Forms.Context dependencies * Remove Context/Forms.Context dependencies in Drawable subclasses * Remove some more Forms.Context dependencies * CellAdapter no longer dependent on Forms.Context * Obsolete ToAndroid using Forms.Context * Remove Forms.Context dependencies in ResourceManager * Remove need for Forms.Context for SupportsProgress * Remove Forms.Context dependency for setting titlebar visibility * Remove Forms.Context dependencies in GetAccentColor * Some comments about caching * Remove Forms.Context dependencies for AndroidPlatformServices and ResourceProvider * Remove Forms.Context dependencies in Maps * Disabled warnings for Forms.Context in CustomRenderers * Filter logs so we don't get those annoying "parked" messages * Filter alerts/actionsheets/activityindicator by context * Clean up constructor debugging messages * Remove old TODOs * Set up test page for Device.Openuri * Make AndroidDeviceInfo more resilient to multiple activity scenarios * Use parameter instead of member * Add missing parameterless constructors for embedded fragment wrappers * Fix multiple popup subscriptions for embedded context * Remove UpdateGlobalContext and Page Context attached property * Obsolete static reference to Context * Warnings as errors in embedded test bed projects * Comment cleanup * Clean up unused code * Obsolete old constructor for DefaultRenderer * Make sure embedded fragment wrappers handle disposing the platform * Revert to old DependencyService registration for ResourceProvider; use ApplicationContext for ResourceProvider; Comments for everything happing in Forms.SetupInit * Remove old TODO * Make PopupManager take the correct type instead of casting a bunch * Update docs * Add missing nuspec entry for FormsEmbeddedPageWrapper * Post-rebase cleanup * Update docs * Disable XF target validation so package restore works * Restore InputTransparent handling lost in rebase * Restore parameter lost during rebase * Finalize the list of subscriptions to avoid 'modified collection' errors * Avoid double-fetching Context * Fix "with you package" typo
2017-10-09 20:51:55 +03:00
Drawable iconDrawable = _context.GetFormsDrawable(icon);
if (iconDrawable != null)
item.SetIcon(iconDrawable);
}
2016-03-22 23:02:25 +03:00
action.PropertyChanged += changed;
action.PropertyChanging += changing;
if (action.Command != null)
action.Command.CanExecuteChanged += commandChanged;
if (!((IMenuItemController)action).IsEnabled)
2016-03-22 23:02:25 +03:00
item.SetEnabled(false);
}
}
bool HandleContextMode(AView view, int position)
{
if (view is EditText || view is TextView || view is SearchView)
return false;
2016-03-22 23:02:25 +03:00
Cell cell = GetCellForPosition(position);
if (cell == null)
return false;
2016-03-22 23:02:25 +03:00
if (_actionMode != null || _supportActionMode != null)
{
if (!cell.HasContextActions)
{
CloseContextActions();
2016-03-22 23:02:25 +03:00
return false;
}
ActionModeContext = cell;
_actionMode?.Invalidate();
_supportActionMode?.Invalidate();
}
else
{
if (!cell.HasContextActions)
return false;
ActionModeContext = cell;
[All] Page embedding (#1124) * Fix broken SetTextAppearance call when targeting below API 23 * Enable embedding XF apps in Android * VS didn't save the project file * Allow retrieving rendered XF VisualElements for use in UWP apps * Prevent XF from slaughtering the menu bar in embedded scenarios * ? * Post-rebase fixups * Create embedding test project for Android * Create iOS test bed project * Attempting to get functional embedded project * Android and iOS functional testbed projects * Basic embedding app on UWP * First pass at handling navigation to Forms page from UWP * Fleshed out example, added parameter checks, sealed wrapper class * Create test page and load it from UWP * Make DisplayAlert/DisplayActionSheet independent of Platform instance on UWP * Set up test page for alerts/actionsheets on Android * Move DisplayAlert/ActionSheet code to a helper class so embedded Forms can use it * VS didn't save my changes * Add test page for alerts and action sheets * Get FrameworkElement from renderer * Page -> ContentPage * Can now display the webview embedded page * Example working on iOS * Repro of crash * Remove the IStartActivityForResult dependency from FormsWebChromeClient * Created repro * Remove need for Forms.Context to create renderers * Remove Forms.Context dependencies in ScrollViewRenderer * Remove Forms.Context dependencies in FrameRenderer * Remove Forms.Context dependencies * Remove Context/Forms.Context dependencies in Drawable subclasses * Remove some more Forms.Context dependencies * CellAdapter no longer dependent on Forms.Context * Obsolete ToAndroid using Forms.Context * Remove Forms.Context dependencies in ResourceManager * Remove need for Forms.Context for SupportsProgress * Remove Forms.Context dependency for setting titlebar visibility * Remove Forms.Context dependencies in GetAccentColor * Some comments about caching * Remove Forms.Context dependencies for AndroidPlatformServices and ResourceProvider * Remove Forms.Context dependencies in Maps * Disabled warnings for Forms.Context in CustomRenderers * Filter logs so we don't get those annoying "parked" messages * Filter alerts/actionsheets/activityindicator by context * Clean up constructor debugging messages * Remove old TODOs * Set up test page for Device.Openuri * Make AndroidDeviceInfo more resilient to multiple activity scenarios * Use parameter instead of member * Add missing parameterless constructors for embedded fragment wrappers * Fix multiple popup subscriptions for embedded context * Remove UpdateGlobalContext and Page Context attached property * Obsolete static reference to Context * Warnings as errors in embedded test bed projects * Comment cleanup * Clean up unused code * Obsolete old constructor for DefaultRenderer * Make sure embedded fragment wrappers handle disposing the platform * Revert to old DependencyService registration for ResourceProvider; use ApplicationContext for ResourceProvider; Comments for everything happing in Forms.SetupInit * Remove old TODO * Make PopupManager take the correct type instead of casting a bunch * Update docs * Add missing nuspec entry for FormsEmbeddedPageWrapper * Post-rebase cleanup * Update docs * Disable XF target validation so package restore works * Restore InputTransparent handling lost in rebase * Restore parameter lost during rebase * Finalize the list of subscriptions to avoid 'modified collection' errors * Avoid double-fetching Context * Fix "with you package" typo
2017-10-09 20:51:55 +03:00
var appCompatActivity = view.Context as AppCompatActivity;
2016-03-22 23:02:25 +03:00
if (appCompatActivity == null)
[All] Page embedding (#1124) * Fix broken SetTextAppearance call when targeting below API 23 * Enable embedding XF apps in Android * VS didn't save the project file * Allow retrieving rendered XF VisualElements for use in UWP apps * Prevent XF from slaughtering the menu bar in embedded scenarios * ? * Post-rebase fixups * Create embedding test project for Android * Create iOS test bed project * Attempting to get functional embedded project * Android and iOS functional testbed projects * Basic embedding app on UWP * First pass at handling navigation to Forms page from UWP * Fleshed out example, added parameter checks, sealed wrapper class * Create test page and load it from UWP * Make DisplayAlert/DisplayActionSheet independent of Platform instance on UWP * Set up test page for alerts/actionsheets on Android * Move DisplayAlert/ActionSheet code to a helper class so embedded Forms can use it * VS didn't save my changes * Add test page for alerts and action sheets * Get FrameworkElement from renderer * Page -> ContentPage * Can now display the webview embedded page * Example working on iOS * Repro of crash * Remove the IStartActivityForResult dependency from FormsWebChromeClient * Created repro * Remove need for Forms.Context to create renderers * Remove Forms.Context dependencies in ScrollViewRenderer * Remove Forms.Context dependencies in FrameRenderer * Remove Forms.Context dependencies * Remove Context/Forms.Context dependencies in Drawable subclasses * Remove some more Forms.Context dependencies * CellAdapter no longer dependent on Forms.Context * Obsolete ToAndroid using Forms.Context * Remove Forms.Context dependencies in ResourceManager * Remove need for Forms.Context for SupportsProgress * Remove Forms.Context dependency for setting titlebar visibility * Remove Forms.Context dependencies in GetAccentColor * Some comments about caching * Remove Forms.Context dependencies for AndroidPlatformServices and ResourceProvider * Remove Forms.Context dependencies in Maps * Disabled warnings for Forms.Context in CustomRenderers * Filter logs so we don't get those annoying "parked" messages * Filter alerts/actionsheets/activityindicator by context * Clean up constructor debugging messages * Remove old TODOs * Set up test page for Device.Openuri * Make AndroidDeviceInfo more resilient to multiple activity scenarios * Use parameter instead of member * Add missing parameterless constructors for embedded fragment wrappers * Fix multiple popup subscriptions for embedded context * Remove UpdateGlobalContext and Page Context attached property * Obsolete static reference to Context * Warnings as errors in embedded test bed projects * Comment cleanup * Clean up unused code * Obsolete old constructor for DefaultRenderer * Make sure embedded fragment wrappers handle disposing the platform * Revert to old DependencyService registration for ResourceProvider; use ApplicationContext for ResourceProvider; Comments for everything happing in Forms.SetupInit * Remove old TODO * Make PopupManager take the correct type instead of casting a bunch * Update docs * Add missing nuspec entry for FormsEmbeddedPageWrapper * Post-rebase cleanup * Update docs * Disable XF target validation so package restore works * Restore InputTransparent handling lost in rebase * Restore parameter lost during rebase * Finalize the list of subscriptions to avoid 'modified collection' errors * Avoid double-fetching Context * Fix "with you package" typo
2017-10-09 20:51:55 +03:00
_actionMode = ((Activity)view.Context).StartActionMode(this);
2016-03-22 23:02:25 +03:00
else
_supportActionMode = appCompatActivity.StartSupportActionMode(this);
}
ContextView = view;
return true;
}
void OnActionItemClickedImpl(IMenuItem item)
{
int index = item.ItemId;
IMenuItemController action = ActionModeContext.ContextActions[index];
2016-03-22 23:02:25 +03:00
action.Activate();
}
void OnContextActionCommandCanExecuteChanged(object sender, EventArgs eventArgs)
{
_actionModeNeedsUpdates = true;
_actionMode?.Invalidate();
_supportActionMode?.Invalidate();
2016-03-22 23:02:25 +03:00
}
void OnContextActionPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var action = (MenuItem)sender;
if (e.PropertyName == MenuItem.CommandProperty.PropertyName)
{
if (action.Command != null)
action.Command.CanExecuteChanged += OnContextActionCommandCanExecuteChanged;
}
else
_actionModeNeedsUpdates = true;
}
void OnContextActionPropertyChanging(object sender, PropertyChangingEventArgs e)
{
var action = (MenuItem)sender;
if (e.PropertyName == MenuItem.CommandProperty.PropertyName)
{
if (action.Command != null)
action.Command.CanExecuteChanged -= OnContextActionCommandCanExecuteChanged;
}
}
void OnContextItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
_actionModeNeedsUpdates = true;
_actionMode?.Invalidate();
_supportActionMode?.Invalidate();
2016-03-22 23:02:25 +03:00
}
void OnDestroyActionModeImpl()
{
var changed = new PropertyChangedEventHandler(OnContextActionPropertyChanged);
var changing = new PropertyChangingEventHandler(OnContextActionPropertyChanging);
var commandChanged = new EventHandler(OnContextActionCommandCanExecuteChanged);
((INotifyCollectionChanged)ActionModeContext.ContextActions).CollectionChanged -= OnContextItemsChanged;
for (var i = 0; i < ActionModeContext.ContextActions.Count; i++)
{
MenuItem action = ActionModeContext.ContextActions[i];
action.PropertyChanged -= changed;
action.PropertyChanging -= changing;
if (action.Command != null)
action.Command.CanExecuteChanged -= commandChanged;
}
ContextView = null;
ActionModeContext = null;
_actionModeNeedsUpdates = false;
}
bool OnPrepareActionModeImpl(IMenu menu)
{
if (_actionModeNeedsUpdates)
{
_actionModeNeedsUpdates = false;
menu.Clear();
CreateContextMenu(menu);
}
return false;
}
}
}