2017-10-18 27 views
0

Je rencontre un problème où glisser des cellules dans ma vue recycleur entraîne l'application de lancer une erreur de signal 11. Après avoir examiné ce problème sur google/stackoverflow, j'ai découvert que certaines personnes semblaient pouvoir résoudre le problème en définissant le calque d'une vue sur le rendu logiciel plutôt que sur le rendu accéléré par le matériel - malheureusement, dans mon cas, cela n'a pas été corrigé. la question pour moi, et je n'ai pas pu trouver des suggestions qui étaient vraiment différentes de la réparer comme ça.Fatal Signal 11 erreur lors du dessin sur toile

J'ai tenté de résoudre ce problème en définissant le «conteneur» avec cette méthode ainsi que la ItemView du viewholder - ni l'un ni l'autre n'a empêché l'erreur.

Est-ce que quelqu'un est capable de me dire ce qui est si spécial dans mon scénario que je n'arrive pas à le faire fonctionner?

L'erreur se produit avec la ligne 242 de LeftRightSwipeController.cs

L'échantillon complet de reproduction est disponible sur GitHub à: https://github.com/devsolvum/Signal-11-CanvasDraw

LeftRightSwipeController.cs

using System; 
using System.Collections.Generic; 
using System.Threading; 
using Android.Graphics; 
using Android.Support.V7.Widget; 
using Android.Support.V7.Widget.Helper; 
using Android.Views; 
using Math = Java.Lang.Math; 
using Object = Java.Lang.Object; 

namespace App1.Domain 
{ 
    // https://medium.com/@fanfatal/android-swipe-menu-with-recyclerview-8f28a235ff28 
    // https://github.com/FanFataL/swipe-controller-demo/blob/master/app/src/main/java/pl/fanfatal/swipecontrollerdemo/SwipeController.java 

    public enum SwipeState 
    { 
     Default, 
     LeftOpen, 
     RightOpen 
    } 

    public class LeftRightSwipeController : ItemTouchHelper.Callback 
    { 
     private bool _swipeBack = false; 

     private SwipeState _currentSwipeState = SwipeState.Default; 

     private RectF _buttonInstance = null; 

     public override int ConvertToAbsoluteDirection(int flags, int layoutDirection) 
     { 
      if (_swipeBack) 
      { 
       _swipeBack = _currentSwipeState != SwipeState.Default; 
       return 0; 
      } 
      return base.ConvertToAbsoluteDirection(flags, layoutDirection); 
     } 

     public override void OnChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, 
      float dY, int actionState, bool isCurrentlyActive) 
     { 
      var measuredsize = GetMeasuredSize(GetContainerArea(dX), viewHolder); 
      if (measuredsize.width <= 0 || measuredsize.height <= 0) 
       return; 

      var clippedX = dX >= 0 ? Math.Min(dX, measuredsize.width) : Math.Max(dX, -measuredsize.width); 

      if (actionState == ItemTouchHelper.ActionStateSwipe) 
      { 
       if (_currentSwipeState != SwipeState.Default) 
       { 
        if (_currentSwipeState == SwipeState.LeftOpen) 
         clippedX = Math.Max(clippedX, measuredsize.width); 
        if (_currentSwipeState == SwipeState.RightOpen) 
         clippedX = Math.Min(clippedX, -measuredsize.width); 

        base.OnChildDraw(c, recyclerView, viewHolder, clippedX, dY, actionState, isCurrentlyActive); 
       } 
       else 
       { 
        SetTouchListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 
       } 
      } 

      if (_currentSwipeState == SwipeState.Default) 
      { 
       base.OnChildDraw(c, recyclerView, viewHolder, clippedX, dY, actionState, isCurrentlyActive); 
      } 

      DrawButtons(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive, _currentSwipeState, false); 
     } 

     private (int width, int height) GetMeasuredSize(int containerArea, RecyclerView.ViewHolder viewHolder) 
     { 
      if (viewHolder is IViewHolderButtonContainer buttonContainer) 
      { 
       int widthSpec = View.MeasureSpec.MakeMeasureSpec(viewHolder.ItemView.Width, MeasureSpecMode.AtMost); 
       int heightSpec = View.MeasureSpec.MakeMeasureSpec(viewHolder.ItemView.Height, MeasureSpecMode.AtMost); 

       var container = buttonContainer.CreateButtonContainer(containerArea); 
       container.Measure(widthSpec, heightSpec); 

       return (container.MeasuredWidth, container.MeasuredHeight); 
      } 

      return (0, 0); 
     } 

     private void SetItemsClickable(RecyclerView recyclerView, bool isClickable) 
     { 
      for (int i = 0; i < recyclerView.ChildCount; ++i) 
      { 
       recyclerView.GetChildAt(i).Clickable = isClickable; 
      } 
     } 

     private void SetTouchListener(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, 
      float dY, int actionState, bool isCurrentlyActive) 
     { 
      recyclerView.SetOnTouchListener(
       new TouchListenerDelegate(
        (v, @event) => 
        { 
         _swipeBack = @event.Action == MotionEventActions.Cancel || @event.Action == MotionEventActions.Up; 
         if (_swipeBack) 
         { 
          float containerWidth = GetMeasuredSize(GetContainerArea(dX), viewHolder).width; 

          if (dX <= -containerWidth) 
          { 
           _currentSwipeState = SwipeState.RightOpen; 
          } 
          else if (dX >= containerWidth) 
          { 
           _currentSwipeState = SwipeState.LeftOpen; 
          } 

          if (_currentSwipeState != SwipeState.Default) 
          { 
           DrawButtons(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive, _currentSwipeState, true); 
           SetTouchDownListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 
           SetItemsClickable(recyclerView, false); 
          } 
         } 

         return false; 
        })); 
     } 

     private void SetTouchDownListener(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, 
      float dY, int actionState, bool isCurrentlyActive) 
     { 
      recyclerView.SetOnTouchListener(
       new TouchListenerDelegate(
        (view, args) => 
        { 
         if (args.Action == MotionEventActions.Down) 
         { 
          SetTouchUpListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 
         } 
         return false; 
        })); 
     } 

     private void SetTouchUpListener(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, 
      float dY, int actionState, bool isCurrentlyActive) 
     { 
      recyclerView.SetOnTouchListener(
       new TouchListenerDelegate(
        (recyclerViewInDelegate, outerArgs) => 
        { 
         if (outerArgs.Action == MotionEventActions.Up) 
         { 
          recyclerView.SetOnTouchListener(
           new TouchListenerDelegate(
            (innerView, innerArgs) => { return false; })); 

          SetItemsClickable(recyclerView, true); 
          _swipeBack = false; 

          //       if (_buttonsActions != null && _buttonInstance != null && 
          //        _buttonInstance.Contains(outerArgs.GetX(), outerArgs.GetY())) 
          //       { 
          //        if (_currentSwipeState == SwipeState.LeftOpen) 
          //        { 
          //         _buttonsActions.OnLeftClicked(viewHolder.AdapterPosition); 
          //        } 
          //        else if (_currentSwipeState == SwipeState.RightOpen) 
          //        { 
          //         _buttonsActions.OnRightClicked(viewHolder.AdapterPosition); 
          //        } 
          //       } 

          _currentSwipeState = SwipeState.Default; 


          // folgende codezeile behebt einen darstellungsbug, wenn man eine schaltfläche klickt 
          Thread.Sleep(100); 
          base.OnChildDraw(c, recyclerView, viewHolder, 0, dY, actionState, isCurrentlyActive); 
         } 

         return false; 
        })); 
     } 


     private void DrawButtons(Canvas canvas, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, 
      float dY, int actionState, bool isCurrentlyActive, SwipeState swipeState, bool swipeEnd) 
     { 
      var validState = isCurrentlyActive || swipeState != SwipeState.Default; 


      if (!validState) 
       return; 

      if (viewHolder is IViewHolderButtonContainer buttonContainer) 
      { 
       //    int widthSpec = View.MeasureSpec.MakeMeasureSpec(ViewGroup.LayoutParams.WrapContent, MeasureSpecMode.Unspecified); 

       int widthSpec = View.MeasureSpec.MakeMeasureSpec(viewHolder.ItemView.Width, MeasureSpecMode.AtMost); 
       int heightSpec = View.MeasureSpec.MakeMeasureSpec(viewHolder.ItemView.Height, MeasureSpecMode.AtMost); 

       var containerArea = GetContainerArea(dX); 
       var container = buttonContainer.CreateButtonContainer(containerArea); 
       container.Measure(widthSpec, heightSpec); 

       var clippedWidth = GetClippedWidth(viewHolder.ItemView.Width, dX, container.MeasuredWidth); 
       if (clippedWidth <= 0) 
        return; 
       var clippedHeight = GetClippedHeight(viewHolder.ItemView.Height, dY, container.MeasuredHeight); 
       if (clippedHeight <= 0) 
        return; 

       var viewLeft = dX >= 0 ? viewHolder.ItemView.Left : viewHolder.ItemView.Right - clippedWidth; 
       var viewTop = viewHolder.ItemView.Top; 
       var viewRight = viewLeft + clippedWidth; 
       var viewBottom = viewTop + clippedHeight; 

       container.Layout(viewLeft, viewTop, viewRight, viewBottom); 

       container.SetBackgroundColor(Color.Orange); 

       //    var canvasX = dX >= 0 ? viewHolder.ItemView.Left : viewHolder.ItemView.Left + viewHolder.ItemView.Width; 

       //     var paint = new Paint(); 
       //     paint.Color = Color.Aqua; 
       //     canvas.DrawRect(viewLeft, viewTop, viewRight, viewBottom, paint); 

       // Translate the canvas so the view is drawn at the proper coordinates 
       canvas.Save(); 
       canvas.Translate(viewLeft, viewHolder.ItemView.Top); 

       if (swipeEnd) 
       { 
        viewHolder.ItemView.Invalidate(); 
        container.Invalidate(); 
       } 

       //Draw the View and clear the translation 
       container.Draw(canvas); 
       canvas.Restore(); 
      } 
     } 

     private static int GetContainerArea(float dX) 
     { 
      return dX >= 0 ? 0 : 1; 
     } 

     private int GetClippedHeight(int viewHolderHeight, float dY, int measured) 
     { 
      return viewHolderHeight; 
     } 

     private int GetClippedWidth(int viewHolderWidth, float dX, int measured) 
     { 
      if (viewHolderWidth <= 0) 
       return 0; 

      return Math.Min(measured, (int) Math.Ceil(Math.Abs(dX))); 
     } 


     public override int GetMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) 
     { 
      return MakeMovementFlags(0, ItemTouchHelper.Left | ItemTouchHelper.Right); 
     } 

     public override bool OnMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, 
      RecyclerView.ViewHolder target) 
     { 
      return false; 
     } 

     public override void OnSwiped(RecyclerView.ViewHolder viewHolder, int direction) 
     { 
     } 

     private class TouchListenerDelegate : Object, View.IOnTouchListener 
     { 
      public void Dispose() 
      { 
       Callback = null; 
      } 

      public TouchListenerDelegate(Func<View, MotionEvent, bool> callback) 
      { 
       Callback = callback; 
      } 

      public Func<View, MotionEvent, bool> Callback { get; set; } 

      public bool OnTouch(View v, MotionEvent e) 
      { 
       return Callback(v, e); 
      } 
     } 
    } 

    public interface IViewHolderButtonContainer 
    { 
     /// <summary> 
     /// Erstellt container für die Buttons 
     /// </summary> 
     /// <param name="containerArea">0 = links, 1 = rechts</param> 
     /// <returns></returns> 
     View CreateButtonContainer(int containerArea); 
    } 
} 

MainActivity.cs

using System; 
using System.Collections.Generic; 
using Android.App; 
using Android.Content; 
using Android.Graphics; 
using Android.Widget; 
using Android.OS; 
using Android.Runtime; 
using Android.Support.V7.Widget; 
using Android.Support.V7.Widget.Helper; 
using Android.Views; 
using App1.Domain; 

namespace App1 
{ 
    [Activity(Label = "App1", MainLauncher = true)] 
    public class MainActivity : Activity 
    { 
     protected override void OnCreate(Bundle savedInstanceState) 
     { 
      base.OnCreate(savedInstanceState); 

      // Set our view from the "main" layout resource 
      var mainView = LayoutInflater.Inflate(Resource.Layout.Main, null, true) as LinearLayout; 
      SetContentView(mainView); 
      mainView.SetBackgroundColor(Color.Red); 
      var recyclerView = new RecyclerView(this); 
      var recyclerAdapter = new RecyclerAdapter(); 
      for (int i = 0; i < 30; i++) 
      { 
       recyclerAdapter.Items.Add($"Entry {i}."); 
      } 
      recyclerView.SetAdapter(recyclerAdapter); 
      var linearLayoutManager = new LinearLayoutManager(this); 
      var swipeController = new LeftRightSwipeController(); 
      var ith = new ItemTouchHelper(swipeController); 
      ith.AttachToRecyclerView(recyclerView); 
      recyclerView.SetLayoutManager(linearLayoutManager); 
      recyclerView.SetBackgroundColor(Color.Orange); 
      mainView.AddView(recyclerView); 
     } 

     public class RecyclerAdapter : RecyclerView.Adapter 
     { 
      public List<string> Items { get; set; } = new List<string>(); 

      public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position) 
      { 
       var data = Items[position]; 
       var textView = holder.ItemView.FindViewById<TextView>(Android.Resource.Id.Text1); 
       if (textView != null) 
       { 
        textView.Text = data; 
       } 
      } 

      public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) 
      { 
       var inflater = Android.Views.LayoutInflater.FromContext(parent.Context); 
       var view = inflater.Inflate(Android.Resource.Layout.SimpleListItem1, parent, false); 
       return new CustomViewHolder(view); 
      } 

      public override int ItemCount => Items.Count; 
     } 

     public class CustomViewHolder : RecyclerView.ViewHolder, IViewHolderButtonContainer 
     { 
      public CustomViewHolder(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) 
      { 
      } 

      public CustomViewHolder(View itemView) : base(itemView) 
      { 
      } 

      private View _leftContainer; 
      private View _rightContainer; 

      public View CreateButtonContainer(int containerArea) 
      { 
       if (containerArea == 0) 
       { 
        return _leftContainer ?? (_leftContainer = CreateContainer(containerArea)); 
       } 
       else 
       { 
        return _rightContainer ?? (_rightContainer = CreateContainer(containerArea)); 
       } 
      } 

      private string GetButtonText(int containerArea) 
      { 
       return $"Button area {containerArea}"; 
      } 

      private View CreateContainer(int containerArea) 
      { 
       var textView = new TextView(Android.App.Application.Context); 
       textView.SetBackgroundColor(Color.Blue); 
       textView.Text = GetButtonText(containerArea); 
       return textView; 
      } 
     } 
    } 
} 

Toutes les suggestions pour essayer de résoudre ce problème sont les bienvenues.

Répondre

0

La définition du type de couche sur la vue de recyclage vers le logiciel a résolu le problème. Il s'avère que j'ai choisi la mauvaise vue pour le définir.