I was trying to create a Sliding-Tab-Layout. I followed this tutorial Sliding Tab Layout
and it was great, but I wanted to Load Specific Layout in each TabView
I also want to make each one loaded, when I select it or scroll to it just like facebook application.
The reason is not to take so much time to load for each View in ViewPager
and there is the classes:
SlidingTabStrip
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Graphics;
using Android.Util;
namespace SlidingTabLayoutTutorial
{
public class SlidingTabStrip : LinearLayout
{
//Copy and paste from here................................................................
private const int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0;
private const byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0X26;
private const int SELECTED_INDICATOR_THICKNESS_DIPS = 3;
private int[] INDICATOR_COLORS = { 0xffffff };
private int[] DIVIDER_COLORS = { 0xffffff };
private const int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
private const float DEFAULT_DIVIDER_HEIGHT = 0.5f;
//Bottom border
private int mBottomBorderThickness;
private Paint mBottomBorderPaint;
private int mDefaultBottomBorderColor;
//Indicator
private int mSelectedIndicatorThickness;
private Paint mSelectedIndicatorPaint;
//Divider
private Paint mDividerPaint;
private float mDividerHeight;
//Selected position and offset
private int mSelectedPosition;
private float mSelectionOffset;
//Tab colorizer
private SlidingTabScrollView.TabColorizer mCustomTabColorizer;
private SimpleTabColorizer mDefaultTabColorizer;
//Stop copy and paste here........................................................................
//Constructors
public SlidingTabStrip (Context context) : this(context, null)
{ }
public SlidingTabStrip (Context context, IAttributeSet attrs) : base(context, attrs)
{
SetWillNotDraw(false);
float density = Resources.DisplayMetrics.Density;
TypedValue outValue = new TypedValue();
context.Theme.ResolveAttribute(Android.Resource.Attribute.ColorForeground, outValue, true);
int themeForeGround = outValue.Data;
mDefaultBottomBorderColor = SetColorAlpha(themeForeGround, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
mDefaultTabColorizer = new SimpleTabColorizer();
mDefaultTabColorizer.IndicatorColors = INDICATOR_COLORS;
mDefaultTabColorizer.DividerColors = DIVIDER_COLORS;
mBottomBorderThickness = (int)(DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
mBottomBorderPaint = new Paint();
mBottomBorderPaint.Color = GetColorFromInteger(0x1B729E); //Gray
mSelectedIndicatorThickness = (int)(SELECTED_INDICATOR_THICKNESS_DIPS * density);
mSelectedIndicatorPaint = new Paint();
mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
mDividerPaint = new Paint();
mDividerPaint.StrokeWidth = (int)(DEFAULT_DIVIDER_THICKNESS_DIPS * density);
}
public SlidingTabScrollView.TabColorizer CustomTabColorizer
{
set
{
mCustomTabColorizer = value;
this.Invalidate();
}
}
public int [] SelectedIndicatorColors
{
set
{
mCustomTabColorizer = null;
mDefaultTabColorizer.IndicatorColors = value;
this.Invalidate();
}
}
public int [] DividerColors
{
set
{
mDefaultTabColorizer = null;
mDefaultTabColorizer.DividerColors = value;
this.Invalidate();
}
}
private Color GetColorFromInteger(int color)
{
return Color.Rgb(Color.GetRedComponent(color), Color.GetGreenComponent(color), Color.GetBlueComponent(color));
}
private int SetColorAlpha(int color, byte alpha)
{
return Color.Argb(alpha, Color.GetRedComponent(color), Color.GetGreenComponent(color), Color.GetBlueComponent(color));
}
public void OnViewPagerPageChanged(int position, float positionOffset)
{
mSelectedPosition = position;
mSelectionOffset = positionOffset;
this.Invalidate();
}
protected override void OnDraw(Canvas canvas)
{
int height = Height;
int tabCount = ChildCount;
int dividerHeightPx = (int)(Math.Min(Math.Max(0f, mDividerHeight), 1f) * height);
SlidingTabScrollView.TabColorizer tabColorizer = mCustomTabColorizer != null ? mCustomTabColorizer : mDefaultTabColorizer;
//Thick colored underline below the current selection
if (tabCount > 0)
{
View selectedTitle = GetChildAt(mSelectedPosition);
int left = selectedTitle.Left;
int right = selectedTitle.Right;
int color = tabColorizer.GetIndicatorColor(mSelectedPosition);
if (mSelectionOffset > 0f && mSelectedPosition < (tabCount - 1))
{
int nextColor = tabColorizer.GetIndicatorColor(mSelectedPosition + 1);
if (color != nextColor)
{
color = blendColor(nextColor, color, mSelectionOffset);
}
View nextTitle = GetChildAt(mSelectedPosition + 1);
left = (int)(mSelectionOffset * nextTitle.Left + (1.0f - mSelectionOffset) * left);
right = (int)(mSelectionOffset * nextTitle.Right + (1.0f - mSelectionOffset) * right);
}
mSelectedIndicatorPaint.Color = GetColorFromInteger(color);
canvas.DrawRect(left, height - mSelectedIndicatorThickness, right, height, mSelectedIndicatorPaint);
//Creat vertical dividers between tabs
int separatorTop = (height - dividerHeightPx) / 2;
for (int i = 0; i < ChildCount -1; i++)
{
View child = GetChildAt(i);
mDividerPaint.Color = GetColorFromInteger(tabColorizer.GetDividerColor(i));
canvas.DrawLine(child.Right, separatorTop, child.Right, separatorTop + dividerHeightPx, mDividerPaint);
}
canvas.DrawRect(0, height - mBottomBorderThickness, Width, height, mBottomBorderPaint);
}
}
private int blendColor(int color1, int color2, float ratio)
{
float inverseRatio = 1f - ratio;
float r = (Color.GetRedComponent(color1) * ratio) + (Color.GetRedComponent(color2) * inverseRatio);
float g = (Color.GetGreenComponent(color1) * ratio) + (Color.GetGreenComponent(color2) * inverseRatio);
float b = (Color.GetBlueComponent(color1) * ratio) + (Color.GetBlueComponent(color2) * inverseRatio);
return Color.Rgb((int)r, (int)g, (int)b);
}
private class SimpleTabColorizer : SlidingTabScrollView.TabColorizer
{
private int[] mIndicatorColors;
private int[] mDividerColors;
public int GetIndicatorColor(int position)
{
return mIndicatorColors[position % mIndicatorColors.Length];
}
public int GetDividerColor (int position)
{
return mDividerColors[position % mDividerColors.Length];
}
public int[] IndicatorColors
{
set { mIndicatorColors = value; }
}
public int[] DividerColors
{
set { mDividerColors = value; }
}
}
}
}
SlidingTabScrollView
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
using Android.Util;
using Android.Graphics;
namespace SlidingTabLayoutTutorial
{
public class SlidingTabScrollView : HorizontalScrollView
{
private const int TITLE_OFFSET_DIPS = 15;
private const int TAB_VIEW_PADDING_DIPS = 15;
private const int TAB_VIEW_TEXT_SIZE_SP = 20;
private int mTitleOffset;
//private int mTabViewLayoutID;
//private int mTabViewTextViewID;
private ViewPager mViewPager;
private ViewPager.IOnPageChangeListener mViewPagerPageChangeListener;
private static SlidingTabStrip mTabStrip;
private int mScrollState;
public interface TabColorizer
{
int GetIndicatorColor(int position);
int GetDividerColor(int position);
}
public SlidingTabScrollView(Context context) : this(context, null) { }
public SlidingTabScrollView(Context context, IAttributeSet attrs) : this(context, attrs, 0) { }
public SlidingTabScrollView (Context context, IAttributeSet attrs, int defaultStyle) : base(context, attrs, defaultStyle)
{
//Disable the scroll bar
HorizontalScrollBarEnabled = false;
//Make sure the tab strips fill the view
FillViewport = true;
this.SetBackgroundColor(Android.Graphics.Color.ParseColor("#0078FF")); //Gray color
mTitleOffset = (int)(TITLE_OFFSET_DIPS * Resources.DisplayMetrics.Density);
mTabStrip = new SlidingTabStrip(context);
mTabStrip.WeightSum = 3;
this.AddView(mTabStrip, LayoutParams.MatchParent, LayoutParams.MatchParent);
}
public TabColorizer CustomTabColorizer
{
set { mTabStrip.CustomTabColorizer = value; }
}
public int [] SelectedIndicatorColor
{
set { mTabStrip.SelectedIndicatorColors = value; }
}
public int [] DividerColors
{
set { mTabStrip.DividerColors = value; }
}
public ViewPager.IOnPageChangeListener OnPageListener
{
set { mViewPagerPageChangeListener = value; }
}
public ViewPager ViewPager
{
set
{
mTabStrip.RemoveAllViews();
mViewPager = value;
if (value != null)
{
value.PageSelected += value_PageSelected;
value.PageScrollStateChanged += value_PageScrollStateChanged;
value.PageScrolled += value_PageScrolled;
PopulateTabStrip();
}
}
}
void value_PageScrolled(object sender, ViewPager.PageScrolledEventArgs e)
{
int tabCount = mTabStrip.ChildCount;
if ((tabCount == 0) || (e.Position < 0) || (e.Position >= tabCount))
{
//if any of these conditions apply, return, no need to scroll
return;
}
mTabStrip.OnViewPagerPageChanged(e.Position, e.PositionOffset);
View selectedTitle = mTabStrip.GetChildAt(e.Position);
int extraOffset = (selectedTitle != null ? (int)(e.Position * selectedTitle.Width) : 0);
ScrollToTab(e.Position, extraOffset);
if (mViewPagerPageChangeListener != null)
{
mViewPagerPageChangeListener.OnPageScrolled(e.Position, e.PositionOffset, e.PositionOffsetPixels);
}
}
void value_PageScrollStateChanged(object sender, ViewPager.PageScrollStateChangedEventArgs e)
{
mScrollState = e.State;
if (mViewPagerPageChangeListener != null)
{
mViewPagerPageChangeListener.OnPageScrollStateChanged(e.State);
}
}
void value_PageSelected(object sender, ViewPager.PageSelectedEventArgs e)
{
if (mScrollState == ViewPager.ScrollStateIdle)
{
mTabStrip.OnViewPagerPageChanged(e.Position, 0f);
ScrollToTab(e.Position, 0);
}
if (mViewPagerPageChangeListener != null)
{
mViewPagerPageChangeListener.OnPageSelected(e.Position);
}
}
private void PopulateTabStrip()
{
PagerAdapter adapter = mViewPager.Adapter;
for (int i = 0; i < adapter.Count; i++)
{
TextView tabView = CreateDefaultTabView(Context);
tabView.Text = ((SlidingTabsFragment.SamplePagerAdapter)adapter).GetHeaderTitle(i);
tabView.SetTextColor(Android.Graphics.Color.White);
tabView.Tag = i;
tabView.Click += tabView_Click;
mTabStrip.AddView(tabView);
}
}
void tabView_Click(object sender, EventArgs e)
{
TextView clickTab = (TextView)sender;
int pageToScrollTo = (int)clickTab.Tag;
mViewPager.CurrentItem = pageToScrollTo;
}
private TextView CreateDefaultTabView(Android.Content.Context context )
{
TextView textView = new TextView(context);
textView.Gravity = GravityFlags.Center;
textView.SetTextSize(ComplexUnitType.Sp, TAB_VIEW_TEXT_SIZE_SP);
textView.Typeface = Android.Graphics.Typeface.Default;
textView.LayoutParameters = new LinearLayout.LayoutParams(0, LayoutParams.MatchParent, 1);
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Honeycomb)
{
TypedValue outValue = new TypedValue();
Context.Theme.ResolveAttribute(Android.Resource.Attribute.SelectableItemBackground, outValue, false);
textView.SetBackgroundResource(outValue.ResourceId);
}
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.IceCreamSandwich)
{
textView.SetAllCaps(true);
}
int padding = (int)(TAB_VIEW_PADDING_DIPS * Resources.DisplayMetrics.Density);
textView.SetPadding(padding, padding, padding, padding);
return textView;
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
if (mViewPager != null)
{
ScrollToTab(mViewPager.CurrentItem, 0);
}
}
private void ScrollToTab(int tabIndex, int extraOffset)
{
int tabCount = mTabStrip.ChildCount;
if (tabCount == 0 || tabIndex < 0 || tabIndex >= tabCount)
{
//No need to go further, dont scroll
return;
}
View selectedChild = mTabStrip.GetChildAt(tabIndex);
if (selectedChild != null)
{
int scrollAmountX = selectedChild.Left + extraOffset;
if (tabIndex >0 || extraOffset > 0)
{
scrollAmountX -= mTitleOffset;
}
this.ScrollTo(scrollAmountX, 0);
}
}
}
}
SlidingTabsFragment
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
namespace SlidingTabLayoutTutorial
{
public class SlidingTabsFragment : Fragment
{
private SlidingTabScrollView mSlidingTabScrollView;
private ViewPager mViewPager;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.Inflate(Resource.Layout.fragment_sample, container, false);
}
public override void OnViewCreated(View view, Bundle savedInstanceState)
{
mSlidingTabScrollView = view.FindViewById<SlidingTabScrollView>(Resource.Id.sliding_tabs);
mViewPager = view.FindViewById<ViewPager>(Resource.Id.viewpager);
mViewPager.Adapter = new SamplePagerAdapter();
mSlidingTabScrollView.ViewPager = mViewPager;
}
public class SamplePagerAdapter : PagerAdapter
{
List<string> items = new List<string>();
public SamplePagerAdapter() : base()
{
items.Add("Home");
items.Add("Sell");
items.Add("Rent");
}
public override int Count
{
get { return items.Count; }
}
public override bool IsViewFromObject(View view, Java.Lang.Object obj)
{
return view == obj;
}
public override Java.Lang.Object InstantiateItem(ViewGroup container, int position)
{
View view = LayoutInflater.From(container.Context).Inflate(Resource.Layout.pager_item, container, false);
container.AddView(view);
TextView txtTitle = view.FindViewById<TextView>(Resource.Id.item_title);
int pos = position + 1;
txtTitle.Text = pos.ToString();
return view;
}
public string GetHeaderTitle (int position)
{
return items[position];
}
public override void DestroyItem(ViewGroup container, int position, Java.Lang.Object obj)
{
container.RemoveView((View)obj);
}
}
}
}
MainActivity
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Support.V4.View;
namespace SlidingTabLayoutTutorial
{
[Activity(Label = "Sliding Tab Layout", MainLauncher = true, Icon = "#drawable/xs")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
FragmentTransaction transaction = FragmentManager.BeginTransaction();
SlidingTabsFragment fragment = new SlidingTabsFragment();
transaction.Replace(Resource.Id.sample_content_fragment, fragment);
transaction.Commit();
}
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.actionbar_main, menu);
return base.OnCreateOptionsMenu(menu);
}
}
}
I think you need to add in your code something like this : (in OnCreateView() )
position => comes from the adapter..
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
switch (position)
{
case 0:
view = (ViewGroup)inflater.Inflate(Resource.Layout.Page1, container, false);
break;
case 1:
view = (ViewGroup)inflater.Inflate(Resource.Layout.Page2, container, false);
btn_forexample = view.FindViewById<Button>(Resource.Id.btn_forexample);
break;
case 2:
view = (ViewGroup)inflater.Inflate(Resource.Layout.Page3, container, false);
break;
default:
view = (ViewGroup)inflater.Inflate(Resource.Layout.DefaultPage, container, false);
break;
}
return view;
}
Hope it helps ;)
Related
I've begun working on an early alpha menu for my game and I've was wondering how to exclude items in an array, specifically in unity. I'm trying to make every item except the currently used one. I don't know how I should go about it, if anyone could help, that would be amazing.
here's my current code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class CS
{
public List<GameObject> CanvasButtons;
}
public class CanvasSwitcher : MonoBehaviour
{
public List<CS> Screen = new List<CS>();
static int switcher;
public static void ScreenSwitchPlus()
{
switcher += 1;
}
public static void ScreenSwitchMinus()
{
switcher -= 1;
}
public void Update()
{
foreach(GameObject l in Screen[switcher].CanvasButtons)
{
l.SetActive(true);
}
}
}
It would be wiser to use for loop instead of foreach loop here:
public void Update()
{
int ignore = 2;
for(int i = 0; i < Screen[switcher].CanvasButtons.Count; i++)
{
if(i != ignore)
Screen[switcher].CanvasButtons[i].SetActive(true);
else
Screen[switcher].CanvasButtons[i].SetActive(false);
}
}
It could be even shorter without if (admit less readable):
public void Update()
{
int ignore = 2;
for(int i = 0; i < Screen[switcher].CanvasButtons.Count; i++)
{
Screen[switcher].CanvasButtons[i].SetActive(i != ignore);
}
}
... and even shorter with taking CanvasButtons out of loop:
public void Update()
{
int ignore = 2;
var collection = Screen[switcher].CanvasButtons;
for(int i = 0; i < collection.Count; i++)
{
collection[i].SetActive(i != ignore);
}
}
I got it! I was a bit null-brained for a while there, I messed up a few values in the second for statement, but I got it. I'll post the code here. I keep forgetting little things in the math. Like I always say, I don't solve problems, I make them.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class CS
{
public List<GameObject> CanvasButtons;
}
public class CanvasSwitcher : MonoBehaviour
{
public List<CS> Screen = new List<CS>();
static int switcher;
public static void ScreenSwitchPlus()
{
switcher += 1;
}
public static void ScreenSwitchMinus()
{
switcher -= 1;
}
public void FixedUpdate()
{
List<CS> csco = Screen;
for(int i1 = 0; i1 < csco.Count;)
{
List<GameObject> collection = csco[i1].CanvasButtons;
for (int i = 0; i < collection.Count; i++)
{
collection[i].SetActive(i1 == switcher);
switch(i == collection.Count - 1)
{
case true:
i1++;
break;
}
}
}
}
}
I think you are making things too complicated.
It could simply be
public void Update()
{
for(var i = 0; i < Screen.Count; i++)
{
foreach(var button in Screen[i].CanvasButtons)
{
button.SetActive(i == switcher);
}
}
}
Two more points though.
First I would make sure that switcher is actually a valid value. You either want to clamp the value to stay within the index range like
public static void ScreenSwitchPlus()
{
switcher = Mathf.Clamp(switcher + 1, 0, Screen.Count);
}
public static void ScreenSwitchMinus()
{
switcher = Mathf.Clamp(switcher - 1, 0, Screen.Count);
}
or you could implement wrap around at the ends according to your needs like
public static void ScreenSwitchPlus()
{
switcher = (switcher + 1) % Screen.Count;
}
public static void ScreenSwitchMinus()
{
switcher -= 1;
if(switcher < 0) switcher = Screen.Count - 1;
}
and then finally as mentioned I wouldn't do this poll fetching the value in Update every frame at all but rather event driven.
If you really need to (I would claim it is just lazyness ;) ) have that value and methods static you could attach to an event like
private static event Action<int> OnSwitcherChanged;
public static void ScreenSwitchPlus()
{
switcher = (switcher + 1) % Screen.Count;
OnSwitcherChanged?.Invoke(switcher);
}
public static void ScreenSwitchMinus()
{
switcher -= 1;
if(switcher < 0) switcher = Screen.Count - 1;
OnSwitcherChanged?.Invoke(switcher);
}
and then listen to that event like
private void OnEnable()
{
OnSwitcherChanged += HandleSwitchChanged;
}
private void OnDisable()
{
OnSwitcherChanged -= HandleSwitchChanged;
}
private void HandleSwitchChanged(int newIndex)
{
for(var i = 0; i < Screen.Count; i++)
{
foreach(var button in Screen[i].CanvasButtons)
{
button.SetActive(i == switcher);
}
}
}
Try this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class CS {
public List<GameObject> CanvasButtons;
}
public class CanvasSwitcher : MonoBehaviour {
public List<CS> Screen = new List<CS>();
private static bool m_changed = false;
private static int m_lastSwitcher = 0;
private static int m_switcher = 0;
static int switcher {
get {
return m_switcher;
}
set {
if ( switcher != value ) {
m_lastSwitcher = m_switcher;
m_changed = true;
m_switcher = value;
}
}
}
public static void ScreenSwitchPlus() {
switcher += 1;
}
public static void ScreenSwitchMinus() {
switcher -= 1;
}
private void Update() {
if ( m_changed ) {
UpdateCS();
m_changed = false;
}
}
void UpdateCS() {
if ( m_lastSwitcher < Screen.Count ) {
var canvasBtns = Screen[ m_lastSwitcher ].CanvasButtons;
for ( int i = 0; i < canvasBtns.Count; i++ ) {
canvasBtns[ i ].SetActive( false );
}
}
if ( switcher < Screen.Count ) {
var canvasBtns = Screen[ switcher ].CanvasButtons;
for ( int i = 0; i < canvasBtns.Count; i++ ) {
canvasBtns[ i ].SetActive( true );
}
}
}
}
I am running into an issue where swiping cells in my recycler view results in the application throwing a signal 11 error.
After looking into this issue on google/stackoverflow i found out that some people seemed to be able to fix it by setting the layer of a view to software rendering rather than hardware accelerated rendering - unfortunately in my case that did not fix the issue for me, nor was i able to find any suggestions which were really different from fixing it like that.
I attempted to do fix this by setting the "container" with that method as well as the ItemView of the viewholder - neither one prevented the error.
Is someone able to tell me what's so special about my scenario that i can't get it to work?
The error happens with line 242 of LeftRightSwipeController.cs
The full reproduction sample is available on github at:
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;
}
}
}
}
Any suggestions to try and fix this are very welcome.
Setting the layer type on the recyclerview to software fixed the issue. Turns out i picked the wrong view to set it.
I'm working on a final project for school (art school not computer science) where I'd like to make a live visualizer from brainwaves using a NeuroSky Mindwave brain reader and Unity. Unfortunately the teacher has very limited knowledge of coding as well and has left me in a very bad position...
I've built a music visualizer following this tutorial:
https://www.youtube.com/watch?v=ELLANEFw5B8
And also found an example Unity project which can live read and display raw data from the brainwave reader:
https://github.com/tgraupmann/unity_neurosky
Where I'm stuck is in trying to change the input of my visualizer to be the raw brainwave data rather than music.
Is someone able to help me move forward with this project? I've already looked at NeuroSky's Unity integration page and emailed them with no success.
Any help will be greatly appreciated, thanks so much!
Audio Spectrum Visualizer Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spectrum : MonoBehaviour {
// Use this for initialization
public GameObject prefab;
public int numberOfObjects = 20;
public float radius = 5f;
public GameObject[] cubes;
void Start()
{
for (int i = 0; i < numberOfObjects; i++)
{
float angle = i * Mathf.PI * 2 / numberOfObjects;
Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
Instantiate(prefab, pos, Quaternion.identity);
}
cubes = GameObject.FindGameObjectsWithTag ("cubes");
}
// Update is called once per frame
void Update () {
float[] spectrum = AudioListener.GetSpectrumData (1024, 0, FFTWindow.Hamming);
for(int i = 0; i < numberOfObjects; i++)
{
Vector3 previousScale = cubes[i].transform.localScale;
previousScale.y = Mathf.Lerp (previousScale.y, spectrum[i] * 40, Time.deltaTime * 30);
cubes[i].transform.localScale = previousScale;
}
}
}
ThinkGear Connector Controller Code
(as far as I know the file that causes the raw data to be displayed in Unity like the screenshot commented below)
using System;
using System.Threading;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using MindWave.LitJson;
using System.Net.Sockets;
using System.Text;
using System.IO;
namespace MindWave
{
public class TGCConnectionController : MonoBehaviour
{
private TcpClient client;
private Stream stream;
private byte[] buffer;
public delegate void UpdateIntValueDelegate(int value);
public delegate void UpdateFloatValueDelegate(float value);
public event UpdateIntValueDelegate UpdatePoorSignalEvent;
public event UpdateIntValueDelegate UpdateAttentionEvent;
public event UpdateIntValueDelegate UpdateMeditationEvent;
public event UpdateIntValueDelegate UpdateRawdataEvent;
public event UpdateIntValueDelegate UpdateBlinkEvent;
public event UpdateFloatValueDelegate UpdateDeltaEvent;
public event UpdateFloatValueDelegate UpdateThetaEvent;
public event UpdateFloatValueDelegate UpdateLowAlphaEvent;
public event UpdateFloatValueDelegate UpdateHighAlphaEvent;
public event UpdateFloatValueDelegate UpdateLowBetaEvent;
public event UpdateFloatValueDelegate UpdateHighBetaEvent;
public event UpdateFloatValueDelegate UpdateLowGammaEvent;
public event UpdateFloatValueDelegate UpdateHighGammaEvent;
private bool m_waitForExit = true;
private void Start()
{
ThreadStart ts = new ThreadStart(Connect);
Thread thread = new Thread(ts);
thread.Start();
}
public void Disconnect()
{
stream.Close();
}
public void Connect()
{
client = new TcpClient("127.0.0.1", 13854);
stream = client.GetStream();
buffer = new byte[1024];
byte[] myWriteBuffer = Encoding.ASCII.GetBytes(#"{""enableRawOutput"": true, ""format"": ""Json""}");
stream.Write(myWriteBuffer, 0, myWriteBuffer.Length);
while (m_waitForExit)
{
ParseData();
Thread.Sleep(100);
}
}
public class PowerData
{
public float delta = 0;
public float theta = 0;
public float lowAlpha = 0;
public float highAlpha = 0;
public float lowBeta = 0;
public float highBeta = 0;
public float lowGamma = 0;
public float highGamma = 0;
public PowerData()
{
}
}
public class SenseData
{
public int attention = 0;
public int meditation = 0;
public PowerData eegPower = null;
public SenseData()
{
}
}
public class PackatData
{
public string status = string.Empty;
public int poorSignalLevel = 0;
public int rawEeg = 0;
public int blinkStrength = 0;
public SenseData eSense = null;
public PackatData()
{
}
}
int GetObjectCount(String json)
{
int level = 0;
int count = 0;
for (int i = 0; i < json.Length; ++i)
{
if (json[i].Equals('{'))
{
if (level == 0)
{
++count;
}
++level;
}
if (json[i].Equals('}'))
{
--level;
}
}
return count;
}
private void ParseData()
{
if (stream.CanRead)
{
try
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
List<PackatData> packets = new List<PackatData>();
String packet = Encoding.ASCII.GetString(buffer, 0, bytesRead);
if (!string.IsNullOrEmpty(packet))
{
Debug.Log(packet);
if (packet.Contains("}"))
{
int count = GetObjectCount(packet);
if (count == 1)
{
PackatData data = JsonMapper.ToObject<PackatData>(packet);
packets.Add(data);
}
else if (count > 1)
{
PackatData[] data = JsonMapper.ToObject<PackatData[]>(packet);
for (int index = 0; index < data.Length; ++index)
{
packets.Add(data[index]);
}
}
}
}
foreach (PackatData data in packets)
{
if (null == data)
{
continue;
}
if (data.poorSignalLevel != 0)
{
Debug.Log("data.poorSignalLevel: " + data.poorSignalLevel);
if (null != UpdatePoorSignalEvent)
{
UpdatePoorSignalEvent.Invoke(data.poorSignalLevel);
}
if (null != data.eSense)
{
if (UpdateAttentionEvent != null)
{
UpdateAttentionEvent(data.eSense.attention);
}
if (UpdateMeditationEvent != null)
{
UpdateMeditationEvent(data.eSense.meditation);
}
if (null != data.eSense.eegPower)
{
if (UpdateDeltaEvent != null)
{
UpdateDeltaEvent(data.eSense.eegPower.delta);
}
if (UpdateThetaEvent != null)
{
UpdateThetaEvent(data.eSense.eegPower.theta);
}
if (UpdateLowAlphaEvent != null)
{
UpdateLowAlphaEvent(data.eSense.eegPower.lowAlpha);
}
if (UpdateHighAlphaEvent != null)
{
UpdateHighAlphaEvent(data.eSense.eegPower.highAlpha);
}
if (UpdateLowBetaEvent != null)
{
UpdateLowBetaEvent(data.eSense.eegPower.lowBeta);
}
if (UpdateHighBetaEvent != null)
{
UpdateHighBetaEvent(data.eSense.eegPower.highBeta);
}
if (UpdateLowGammaEvent != null)
{
UpdateLowGammaEvent(data.eSense.eegPower.lowGamma);
}
if (UpdateHighGammaEvent != null)
{
UpdateHighGammaEvent(data.eSense.eegPower.highGamma);
}
}
}
}
else if (data.rawEeg != 0)
{
if (null != UpdateRawdataEvent)
{
UpdateRawdataEvent(data.rawEeg);
}
}
else if (data.blinkStrength != 0)
{
if (null != UpdateRawdataEvent)
{
UpdateBlinkEvent(data.blinkStrength);
}
}
}
}
catch (IOException e)
{
Debug.Log("IOException " + e);
}
catch (System.Exception e)
{
Debug.Log("Exception " + e);
}
}
} // end ParseData
void OnDisable()
{
m_waitForExit = false;
Disconnect();
}
private void OnApplicationQuit()
{
m_waitForExit = false;
Disconnect();
}
}
}
I think you missed the signal processing natural of this problem. Brainwave (if it's Beta wave) has relatively low frequency range, which is about 15 Hz to 30 Hz. Music, on the other hand is audible tone, whose frequency range is between 20 Hz to 20,000 Hz.
I am not familiar with the implementation of this particular visualizer you mentioned here, but if it's implemented as what visualizer suppose to do, the brainwave should show only show some small activity (depends on the amplitude of the brainwave signal) in the lowest frequency range in the spectrum.
There is a potential hack to fix the problem. Usually a visualizer will use FFT to transform a time series signal to its frequency domain, during which it will determine the frequency range the operation is performed over. If you can locate the code in the visualizer and change the frequency range to, say 1 Hz to 100 Hz, you should see a proper frequency spectrum.
I noticed when I resize an element in Visual Studio the Splitter Line is painted in a solid transparent black like this:
However in my own Winforms application I get this resize line:
I am wondering how I can change the painting of this resize line?
If you take a look at Splitter source code, you will see drawing of the highlight is performed in the DrawSplitHelper private method.
Since splitter methods are tightly deppending on private members of the control, overriding members or handling events of the control which use this method doesn't provides such transparent highlight simply. Also if you decide to darw a solid highlight, you can not have a filcker-free drawing because of the halftone highlight which the control draws in private methods.
The idea of showing a transparent highlight is based on showing a top-most semi-transparent window which doesn't activate on showing. Also you can use PatBlt method to draw a reversible rectangle using a brush.
As an option I started by Splitter.cs and changed it to draw desired transparent highlight as you see in image below:
Code
As an option I started by Splitter.cs and changed it to draw desired transparent highlight. I used a Form to show transparent highlight. I showed the form without activating, as top-most and with a suitable opacity.
Probably you can create a splitter using less code, but I preferred to use source code of Splitter instead of writing my own splitter. Thanks to Microsoft for sharing source code.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Drawing.Drawing2D;
using System.Reflection;
[ComVisible(true)]
[DefaultEvent("SplitterMoved")]
[DefaultProperty("Dock")]
[Designer(typeof(MySplitterDesigner))]
public class MySplitter : Control
{
private Point anchor = Point.Empty;
private System.Windows.Forms.BorderStyle borderStyle;
private const int defaultWidth = 3;
private const int DRAW_END = 3;
private const int DRAW_MOVE = 2;
private const int DRAW_START = 1;
private static readonly object EVENT_MOVED = new object();
private static readonly object EVENT_MOVING = new object();
private int initTargetSize;
private int lastDrawSplit = -1;
private int maxSize;
private int minExtra = 25;
private int minSize = 25;
private int splitSize = -1;
private Control splitTarget;
private SplitterMessageFilter splitterMessageFilter;
private int splitterThickness = 3;
[Category("Behavior")]
[Description("Occurs when the splitter is done being moved.")]
public event SplitterEventHandler SplitterMoved
{
add
{
base.Events.AddHandler(EVENT_MOVED, value);
}
remove
{
base.Events.RemoveHandler(EVENT_MOVED, value);
}
}
[Category("Behavior")]
[Description("Occurs when the splitter is being moved.")]
public event SplitterEventHandler SplitterMoving
{
add
{
base.Events.AddHandler(EVENT_MOVING, value);
}
remove
{
base.Events.RemoveHandler(EVENT_MOVING, value);
}
}
HighLight highlight;
public MySplitter()
{
base.SetStyle(ControlStyles.Selectable, false);
this.TabStop = false;
this.minSize = 0x19;
this.minExtra = 0x19;
this.Dock = DockStyle.Left;
highlight = new HighLight();
}
private void ApplySplitPosition()
{
this.SplitPosition = this.splitSize;
}
private SplitData CalcSplitBounds()
{
SplitData data = new SplitData();
Control control = this.FindTarget();
data.target = control;
if (control != null)
{
switch (control.Dock)
{
case DockStyle.Top:
case DockStyle.Bottom:
this.initTargetSize = control.Bounds.Height;
break;
case DockStyle.Left:
case DockStyle.Right:
this.initTargetSize = control.Bounds.Width;
break;
}
Control parentInternal = this.Parent;
Control.ControlCollection controls = parentInternal.Controls;
int count = controls.Count;
int num2 = 0;
int num3 = 0;
for (int i = 0; i < count; i++)
{
Control control3 = controls[i];
if (control3 != control)
{
switch (control3.Dock)
{
case DockStyle.Top:
case DockStyle.Bottom:
num3 += control3.Height;
break;
case DockStyle.Left:
case DockStyle.Right:
num2 += control3.Width;
break;
}
}
}
Size clientSize = parentInternal.ClientSize;
if (this.Horizontal)
{
this.maxSize = (clientSize.Width - num2) - this.minExtra;
}
else
{
this.maxSize = (clientSize.Height - num3) - this.minExtra;
}
data.dockWidth = num2;
data.dockHeight = num3;
}
return data;
}
private Rectangle CalcSplitLine(int splitSize, int minWeight)
{
Rectangle bounds = base.Bounds;
Rectangle rectangle2 = this.splitTarget.Bounds;
switch (this.Dock)
{
case DockStyle.Top:
if (bounds.Height < minWeight)
{
bounds.Height = minWeight;
}
bounds.Y = rectangle2.Y + splitSize;
return bounds;
case DockStyle.Bottom:
if (bounds.Height < minWeight)
{
bounds.Height = minWeight;
}
bounds.Y = ((rectangle2.Y + rectangle2.Height) - splitSize) - bounds.Height;
return bounds;
case DockStyle.Left:
if (bounds.Width < minWeight)
{
bounds.Width = minWeight;
}
bounds.X = rectangle2.X + splitSize;
return bounds;
case DockStyle.Right:
if (bounds.Width < minWeight)
{
bounds.Width = minWeight;
}
bounds.X = ((rectangle2.X + rectangle2.Width) - splitSize) - bounds.Width;
return bounds;
}
return bounds;
}
private int CalcSplitSize()
{
Control control = this.FindTarget();
if (control != null)
{
Rectangle bounds = control.Bounds;
switch (this.Dock)
{
case DockStyle.Top:
case DockStyle.Bottom:
return bounds.Height;
case DockStyle.Left:
case DockStyle.Right:
return bounds.Width;
}
}
return -1;
}
private void DrawSplitBar(int mode)
{
if ((mode != 1) && (this.lastDrawSplit != -1))
{
this.DrawSplitHelper(this.lastDrawSplit);
this.lastDrawSplit = -1;
}
else if ((mode != 1) && (this.lastDrawSplit == -1))
{
return;
}
if (mode != 3)
{
this.DrawSplitHelper(this.splitSize);
this.lastDrawSplit = this.splitSize;
}
else
{
if (this.lastDrawSplit != -1)
{
this.DrawSplitHelper(this.lastDrawSplit);
}
this.lastDrawSplit = -1;
highlight.Hide();
}
Console.WriteLine(mode);
}
private void DrawSplitHelper(int splitSize)
{
if (this.splitTarget != null)
{
Rectangle rectangle = this.CalcSplitLine(splitSize, 3);
var r = this.Parent.RectangleToScreen(rectangle);
if (!highlight.Visible)
highlight.ShowInactiveTopmost();
highlight.Location = r.Location;
highlight.Size = r.Size;
}
}
private Control FindTarget()
{
Control parentInternal = this.Parent;
if (parentInternal != null)
{
Control.ControlCollection controls = parentInternal.Controls;
int count = controls.Count;
DockStyle dock = this.Dock;
for (int i = 0; i < count; i++)
{
Control control2 = controls[i];
if (control2 != this)
{
switch (dock)
{
case DockStyle.Top:
if (control2.Bottom != base.Top)
{
break;
}
return control2;
case DockStyle.Bottom:
if (control2.Top != base.Bottom)
{
break;
}
return control2;
case DockStyle.Left:
if (control2.Right != base.Left)
{
break;
}
return control2;
case DockStyle.Right:
if (control2.Left != base.Right)
{
break;
}
return control2;
}
}
}
}
return null;
}
private int GetSplitSize(int x, int y)
{
int num;
if (this.Horizontal)
num = x - this.anchor.X;
else
num = y - this.anchor.Y;
int num2 = 0;
switch (this.Dock)
{
case DockStyle.Top:
num2 = this.splitTarget.Height + num;
break;
case DockStyle.Bottom:
num2 = this.splitTarget.Height - num;
break;
case DockStyle.Left:
num2 = this.splitTarget.Width + num;
break;
case DockStyle.Right:
num2 = this.splitTarget.Width - num;
break;
}
return Math.Max(Math.Min(num2, this.maxSize), this.minSize);
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if ((this.splitTarget != null) && (e.KeyCode == Keys.Escape))
this.SplitEnd(false);
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if ((e.Button == MouseButtons.Left) && (e.Clicks == 1))
this.SplitBegin(e.X, e.Y);
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (this.splitTarget != null)
{
int x = e.X + base.Left;
int y = e.Y + base.Top;
Rectangle rectangle = this.CalcSplitLine(this.GetSplitSize(e.X, e.Y), 0);
int splitX = rectangle.X;
int splitY = rectangle.Y;
this.OnSplitterMoving(new SplitterEventArgs(x, y, splitX, splitY));
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (this.splitTarget != null)
{
Rectangle rectangle = this.CalcSplitLine(this.GetSplitSize(e.X, e.Y), 0);
this.SplitEnd(true);
}
}
protected virtual void OnSplitterMoved(SplitterEventArgs sevent)
{
SplitterEventHandler handler = (SplitterEventHandler)base.Events[EVENT_MOVED];
if (handler != null)
handler(this, sevent);
if (this.splitTarget != null)
this.SplitMove(sevent.SplitX, sevent.SplitY);
}
protected virtual void OnSplitterMoving(SplitterEventArgs sevent)
{
SplitterEventHandler handler = (SplitterEventHandler)base.Events[EVENT_MOVING];
if (handler != null)
handler(this, sevent);
if (this.splitTarget != null)
this.SplitMove(sevent.SplitX, sevent.SplitY);
}
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
{
if (this.Horizontal)
{
if (width < 1)
width = 3;
this.splitterThickness = width;
}
else
{
if (height < 1)
height = 3;
this.splitterThickness = height;
}
base.SetBoundsCore(x, y, width, height, specified);
}
private void SplitBegin(int x, int y)
{
SplitData data = this.CalcSplitBounds();
if ((data.target != null) && (this.minSize < this.maxSize))
{
this.anchor = new Point(x, y);
this.splitTarget = data.target;
this.splitSize = this.GetSplitSize(x, y);
try
{
if (this.splitterMessageFilter != null)
this.splitterMessageFilter = new SplitterMessageFilter(this);
Application.AddMessageFilter(this.splitterMessageFilter);
}
finally { }
this.Capture = true;
this.DrawSplitBar(1);
}
}
private void SplitEnd(bool accept)
{
this.DrawSplitBar(3);
this.splitTarget = null;
this.Capture = false;
if (this.splitterMessageFilter != null)
{
Application.RemoveMessageFilter(this.splitterMessageFilter);
this.splitterMessageFilter = null;
}
if (accept)
this.ApplySplitPosition();
else if (this.splitSize != this.initTargetSize)
this.SplitPosition = this.initTargetSize;
this.anchor = Point.Empty;
}
private void SplitMove(int x, int y)
{
int splitSize = this.GetSplitSize((x - base.Left) + this.anchor.X, (y - base.Top) + this.anchor.Y);
if (this.splitSize != splitSize)
{
this.splitSize = splitSize;
this.DrawSplitBar(2);
}
}
public override string ToString()
{
string str = base.ToString();
string[] textArray1 = new string[] { str, ", MinExtra: ", this.MinExtra.ToString(CultureInfo.CurrentCulture), ", MinSize: ", this.MinSize.ToString(CultureInfo.CurrentCulture) };
return string.Concat(textArray1);
}
[DefaultValue(0)]
[Category("Appearance")]
[Description("The border type of the control.")]
public System.Windows.Forms.BorderStyle BorderStyle
{
get
{
return this.borderStyle;
}
set
{
if (!IsEnumValid(value, (int)value, 0, 2))
throw new InvalidEnumArgumentException("value", (int)value, typeof(System.Windows.Forms.BorderStyle));
if (this.borderStyle != value)
{
this.borderStyle = value;
base.UpdateStyles();
}
}
}
protected override System.Windows.Forms.CreateParams CreateParams
{
get
{
System.Windows.Forms.CreateParams createParams = base.CreateParams;
createParams.ExStyle &= -513;
createParams.Style &= -8388609;
System.Windows.Forms.BorderStyle borderStyle = this.borderStyle;
if (borderStyle != System.Windows.Forms.BorderStyle.FixedSingle)
{
if (borderStyle == System.Windows.Forms.BorderStyle.Fixed3D)
{
createParams.ExStyle |= 0x200;
}
return createParams;
}
createParams.Style |= 0x800000;
return createParams;
}
}
protected override Cursor DefaultCursor
{
get
{
switch (this.Dock)
{
case DockStyle.Top:
case DockStyle.Bottom:
return Cursors.HSplit;
case DockStyle.Left:
case DockStyle.Right:
return Cursors.VSplit;
}
return base.DefaultCursor;
}
}
protected override System.Windows.Forms.ImeMode DefaultImeMode
{
get
{
return System.Windows.Forms.ImeMode.Disable;
}
}
protected override Size DefaultSize
{
get { return new Size(3, 3); }
}
[Localizable(true), DefaultValue(3)]
public override DockStyle Dock
{
get { return base.Dock; }
set
{
if (((value != DockStyle.Top) && (value != DockStyle.Bottom)) && ((value != DockStyle.Left) && (value != DockStyle.Right)))
throw new ArgumentException("Splitter control must be docked left, right, top, or bottom.");
int splitterThickness = this.splitterThickness;
base.Dock = value;
switch (this.Dock)
{
case DockStyle.Top:
case DockStyle.Bottom:
if (this.splitterThickness == -1)
break;
base.Height = splitterThickness;
return;
case DockStyle.Left:
case DockStyle.Right:
if (this.splitterThickness != -1)
base.Width = splitterThickness;
break;
default:
return;
}
}
}
private bool Horizontal
{
get
{
DockStyle dock = this.Dock;
if (dock != DockStyle.Left)
return (dock == DockStyle.Right);
return true;
}
}
[Category("Behavior")]
[Localizable(true)]
[DefaultValue(25)]
[Description("Specifies the minimum size of the undocked area.")]
public int MinExtra
{
get { return this.minExtra; }
set
{
if (value < 0)
value = 0;
this.minExtra = value;
}
}
[Category("Behavior")]
[Localizable(true)]
[DefaultValue(25)]
[Description("Specifies the minimum size of the control being resized.")]
public int MinSize
{
get { return this.minSize; }
set
{
if (value < 0)
value = 0;
this.minSize = value;
}
}
[Category("Layout")]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Description("The current position of the splitter, or -1 if it is not bound to a control.")]
public int SplitPosition
{
get
{
if (this.splitSize == -1)
{
this.splitSize = this.CalcSplitSize();
}
return this.splitSize;
}
set
{
SplitData data = this.CalcSplitBounds();
if (value > this.maxSize)
{
value = this.maxSize;
}
if (value < this.minSize)
{
value = this.minSize;
}
this.splitSize = value;
this.DrawSplitBar(3);
if (data.target == null)
{
this.splitSize = -1;
}
else
{
Rectangle bounds = data.target.Bounds;
switch (this.Dock)
{
case DockStyle.Top:
bounds.Height = value;
break;
case DockStyle.Bottom:
bounds.Y += bounds.Height - this.splitSize;
bounds.Height = value;
break;
case DockStyle.Left:
bounds.Width = value;
break;
case DockStyle.Right:
bounds.X += bounds.Width - this.splitSize;
bounds.Width = value;
break;
}
data.target.Bounds = bounds;
Application.DoEvents();
this.OnSplitterMoved(new SplitterEventArgs(base.Left, base.Top, base.Left + (bounds.Width / 2), base.Top + (bounds.Height / 2)));
}
}
}
private class SplitData
{
public int dockHeight = -1;
public int dockWidth = -1;
internal Control target;
}
private class SplitterMessageFilter : IMessageFilter
{
private MySplitter owner;
public SplitterMessageFilter(MySplitter splitter)
{
this.owner = splitter;
}
public bool PreFilterMessage(ref Message m)
{
if ((m.Msg < 0x100) || (m.Msg > 0x108))
{
return false;
}
if ((m.Msg == 0x100) && (((int)((long)m.WParam)) == 0x1b))
{
this.owner.SplitEnd(false);
}
return true;
}
}
private static bool IsEnumValid(Enum enumValue, int value, int minValue, int maxValue)
{
return ((value >= minValue) && (value <= maxValue));
}
}
public class MySplitterDesigner : ControlDesigner
{
public MySplitterDesigner() { base.AutoResizeHandles = true; }
private void DrawBorder(Graphics graphics)
{
Color white;
Control control = this.Control;
Rectangle clientRectangle = control.ClientRectangle;
if (control.BackColor.GetBrightness() < 0.5)
white = Color.White;
else
white = Color.Black;
using (Pen pen = new Pen(white))
{
pen.DashStyle = DashStyle.Dash;
clientRectangle.Width--;
clientRectangle.Height--;
graphics.DrawRectangle(pen, clientRectangle);
}
}
protected override void OnPaintAdornments(PaintEventArgs pe)
{
base.OnPaintAdornments(pe);
if (((MySplitter)base.Component).BorderStyle == BorderStyle.None)
this.DrawBorder(pe.Graphics);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x47)
this.Control.Invalidate();
base.WndProc(ref m);
}
}
Here is highlight form:
public class HighLight : Form
{
public HighLight()
{
FormBorderStyle = FormBorderStyle.None;
BackColor = Color.Black;
Opacity = 0;
ShowInTaskbar = false;
StartPosition = FormStartPosition.Manual;
}
protected override void OnDeactivate(EventArgs e)
{
base.OnDeactivate(e);
this.Hide();
}
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(int hWnd, int hWndInsertAfter,
int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public void ShowInactiveTopmost()
{
ShowWindow(this.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(this.Handle.ToInt32(), HWND_TOPMOST,
this.Left, this.Top, this.Width, this.Height,
SWP_NOACTIVATE);
this.Opacity = 0.3;
}
}
I am learning to make a small variant of chess game using windows forms C#, the game includes only the pawns of both sides, i have drew the board and organized the pieces on there places, but i honestly do not know how to start implementing the moves by clicking the mouse on the piece and then the location where i want to move it.
as references the black pawn is named piece, and white pawn is named pieceW
here is my code for the board
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AIchess
{
public partial class Form1 : Form
{
static System.Drawing.Bitmap piece = AIchess.Properties.Resources.piece;
ChessPiece Piece = new ChessPiece(piece, ChessColor.Black);
static System.Drawing.Bitmap pieceW = AIchess.Properties.Resources.pieceW;
ChessPiece PieceW = new ChessPiece(pieceW, ChessColor.White);
Square[,] square = new Square[8, 8];
public Form1()
{
InitializeComponent();
int i, j;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
this.square[i, j] = new Square();
this.square[i, j].BackColor = System.Drawing.SystemColors.ActiveCaption;
this.square[i, j].BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.square[i, j].Location = new System.Drawing.Point(57 + i * 60, 109 + j * 60);
this.square[i, j].Name = i.ToString()+j.ToString();
this.square[i, j].Size = new System.Drawing.Size(60, 60);
this.square[i, j].TabIndex = 2;
this.square[i, j].TabStop = false;
this.Controls.Add(this.square[i, j]);
if (j == 1)
{
this.square[i, j].Image = piece;
this.square[i, j].AllocatedBy = "black";
}
if (j == 6)
{
this.square[i, j].Image = pieceW;
this.square[i, j].AllocatedBy = "white";
}
if (((i+j) % 2) ==0)
this.square[i, j].BackColor = Color.RoyalBlue;
else
this.square[i, j].BackColor = Color.LightBlue;
}
}
}
}
public enum ChessColor
{
White,
Black,
};
class ChessPiece
{
private Image DisplayedImage;
private ChessColor DisplayedColor;
private Point CurrentSquare;
public ChessPiece(Image image, ChessColor color)
{
DisplayedImage = image;
DisplayedColor = color;
}
}
class Square:PictureBox
{
private bool color;
public string AllocatedBy;
}
}
Here's a really simple implementation, I hope you won't mind that I did it from scratch.
Obviously it's very simple, there's no drag and drop and no animation but it fulfills your requirement.
I'll go through each part and explain them
InitializeGame
There you do set your images dimensions (they should be identical obviously)
You add in the dictionary the relationship between piece type/color and your bitmap
Note : the grid will be scaled so you can throw any size of bitmap you like
CreateBoard, DrawGame, DrawPieces
Nothing exceptional in there, note that for keeping things simple I do that every time a user clicks but it shouldn't be much of an issue, it's not Crysis after all :D
PickOrDropPiece
This is the logic where picking/dropping happens, it's really trivial and I'll let you take a look by yourself.
Differences between your code
I've created a Board type which holds the pieces and that you can easily update.
Note : do not remove the equality members in Piece they are here to help the dictionary.
Make sure to use 32-bit bitmaps with transparent borders
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pictureBox1.MouseDown += pictureBox1_MouseDown;
}
#region Properties
private Board Board { get; set; }
private Piece CurrentPiece { get; set; }
private Dictionary<Piece, Bitmap> PieceBitmaps { get; set; }
private int TileWidth { get; set; }
private int TileHeight { get; set; }
#endregion
#region Events
private void Form1_Load(object sender, EventArgs e)
{
InitializeGame();
DrawGame();
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
PickOrDropPiece(e);
DrawGame();
}
#endregion
#region Methods
private void InitializeGame()
{
TileWidth = 64;
TileHeight = 64;
Board = new Board();
PieceBitmaps = new Dictionary<Piece, Bitmap>();
PieceBitmaps.Add(new Piece(PieceType.Pawn, PieceColor.Black), new Bitmap("pawnblack.png"));
PieceBitmaps.Add(new Piece(PieceType.Pawn, PieceColor.White), new Bitmap("pawnwhite.png"));
}
private void DrawGame()
{
var tileSize = new Size(TileWidth, TileHeight);
Bitmap bitmap = CreateBoard(tileSize);
DrawPieces(bitmap);
pictureBox1.Image = bitmap;
}
private Bitmap CreateBoard(Size tileSize)
{
int tileWidth = tileSize.Width;
int tileHeight = tileSize.Height;
var bitmap = new Bitmap(tileWidth*8, tileHeight*8);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 8; y++)
{
Brush brush = (x%2 == 0 && y%2 == 0) || (x%2 != 0 && y%2 != 0) ? Brushes.Black : Brushes.White;
graphics.FillRectangle(brush, new Rectangle(x*tileWidth, y*tileHeight, tileWidth, tileHeight));
}
}
}
return bitmap;
}
private void DrawPieces(Bitmap bitmap)
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
Board board = Board;
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 8; y++)
{
Piece piece = board.GetPiece(x, y);
if (piece != null)
{
Bitmap bitmap1 = PieceBitmaps[piece];
graphics.DrawImageUnscaled(bitmap1, new Point(x*TileWidth, y*TileHeight));
}
}
}
}
}
private void PickOrDropPiece(MouseEventArgs e)
{
Point location = e.Location;
int x = location.X/TileWidth;
int y = location.Y/TileHeight;
bool pickOrDrop = CurrentPiece == null;
if (pickOrDrop)
{
// Pick a piece
Piece piece = Board.GetPiece(x, y);
Board.SetPiece(x, y, null);
if (piece != null)
{
label1.Text = string.Format("You picked a {0} {1} at location {2},{3}", piece.Color, piece.Type, x,
y);
}
else
{
label1.Text = "Nothing there !";
}
CurrentPiece = piece;
}
else
{
// Drop picked piece
Board.SetPiece(x, y, CurrentPiece);
label1.Text = string.Format("You dropped a {0} {1} at location {2},{3}", CurrentPiece.Color,
CurrentPiece.Type, x,
y);
CurrentPiece = null;
}
}
#endregion
}
public class Board
{
private readonly Piece[] _pieces;
public Board()
{
_pieces = new Piece[8*8];
PopulatePieces();
}
public Piece GetPiece(int x, int y)
{
int i = y*8 + x;
return _pieces[i];
}
public void SetPiece(int x, int y, Piece piece)
{
int i = y*8 + x;
_pieces[i] = piece;
}
private void PopulatePieces()
{
for (int i = 0; i < 8; i++)
{
SetPiece(i, 1, new Piece(PieceType.Pawn, PieceColor.Black));
SetPiece(i, 7, new Piece(PieceType.Pawn, PieceColor.White));
}
}
}
public class Piece
{
private readonly PieceColor _color;
private readonly PieceType _type;
public Piece(PieceType type, PieceColor color)
{
_type = type;
_color = color;
}
public PieceType Type
{
get { return _type; }
}
public PieceColor Color
{
get { return _color; }
}
protected bool Equals(Piece other)
{
return _color == other._color && _type == other._type;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((Piece) obj);
}
public override int GetHashCode()
{
unchecked
{
return ((int) _color*397) ^ (int) _type;
}
}
public static bool operator ==(Piece left, Piece right)
{
return Equals(left, right);
}
public static bool operator !=(Piece left, Piece right)
{
return !Equals(left, right);
}
}
public enum PieceType
{
Pawn
}
public enum PieceColor
{
Black,
White
}
}