Android Schiebeschalter [Toggle Switch]

  • VB.NET

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von TRiViUM.

    Android Schiebeschalter [Toggle Switch]

    Android 4.1+ Jelly Bean - Toggle Switch

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Hi liebe Community!


    Ich habe vor, ein Steuerelement zu programmieren, dass dem Android-Schiebeschalter in der Version 4.1+ Jelly Bean ähnelt.

    Ich weiß, dass es bereits ein Thread mit DroidControls gibt, jedoch möchte ich bei dem Schiebeschalter auch nicht auf das
    Schieben verzichten.

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Google's Stock Jelly BeanToggle:




    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Vielleicht bekommen wir ja zusammen am Ende ein schickes Control bei raus, dass ich dann auch gern OpenSource stellen möchte :saint:

    Wenn euch etwas unklar ist , fragt mich einfach ^^

    Vielen Dank für eure Infos :)


    MfG

    Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von „TRiViUM“ ()

    Ich würde keinesfalls von TrackBar erben lassen, wofür auch? Von CheckBox könnte ich ja noch verstehen, aber ich würde einfach nur von Control erben lasssen. Ich würde das MouseDown Event nutzen um die Mouseposition zu ermitteln und zwischenspeichern im MouseMove die aktulle Position zu ermitteln, im MouseUp dann ermitteln ob der Thumb die erfoderliche Distanz verschoben wurde.
    Naja, ich hatte an die Trackbar gedacht, wegen dem Schieber.
    Aber allein von dem Verhalten bzw Events wäre Checkbox schon logischer.

    Die Trackbar, die ich mit entworfen und programmiert habe, habe ich unter Mithilfe eines Forenmitglieds erstellt, der sich allerdings hier abgemeldet hat. ich habe den Code gerade vor mir aber noch nicht so ganz nachvollzogen, wo im Code z.b. definiert wird, dass der Schieber nur horizontal verschiebbar ist, und links und rechts eben einen Anschlag hat.

    Verstehst du, was ich meine?
    Nicht ganz, ich kenne den Code ja nicht. So ein Control kann ich in eines meiner aktuellen Projekte gebrauchen, ich mach nach der Arbeit mal die Basis für das Control, werde den Code dann Posten. Dein Design wirste dann selbst machen müssen.
    Nicht, dass du denkst, ich erwarte hier die ganze Arbeit von den Usern und ich muss den Code dann nur noch einfügen...
    In Sachen GFX kann ich einiges mehr leisten, falls du da was brauchst.

    Nochmal zu meinerm "Problem":
    Den Schieber einer Trackbar kann man nur nach links und nach rechts verschieben, nicht aber auch noch nach oben und unten (bei einer horizontalen anordnung).

    Ich hatte das in Bezug zum Schiebeschalter gedacht, wo ich nicht wusste, wo man im Code festlegt, dass der Schieber eben nur nach links und rechts verschiebbar sein darf.

    Im Anhang mal die besagte Trackbar.


    Danke schonmal für deine Hilfe!
    Dateien
    Okay, da bin ich zu frieden.
    Genau, mit derfuhr. Er hat allerdings auch das meiste programmiert.
    Ich selbst hab lediglich Anpassungen an Farbe/ Abmessungen/ Optierungen vorgenommen, getestet, und kleine Fehler/ Bugs behoben.
    Woher kennst du sie, die Trackbar ? :)
    Grad schnell in der Pause gemacht, denke als Basis geht das in Ordnung.

    VB.NET-Quellcode

    1. <System.ComponentModel.DefaultEvent("CheckedChanged")>
    2. Public Class Toggler
    3. Inherits Control
    4. Private T As Thumb
    5. Private Diff As Integer
    6. Private IsMouseDown As Boolean
    7. Public Event CheckedChanged(sender As Object)
    8. Private _checked As Boolean = False
    9. Public Property Checked As Boolean
    10. Get
    11. Return _checked
    12. End Get
    13. Set(value As Boolean)
    14. If value Then
    15. T.Rect.X = Width - T.Width
    16. Else
    17. T.Rect.X = 0
    18. End If
    19. If _checked <> value Then
    20. _checked = value
    21. RaiseEvent CheckedChanged(Me)
    22. End If
    23. Invalidate()
    24. End Set
    25. End Property
    26. Sub New()
    27. MyBase.New()
    28. SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.UserPaint Or ControlStyles.ResizeRedraw, True)
    29. BackColor = Color.Black
    30. Width = 80
    31. Height = 20
    32. T = New Thumb(Width \ 2, Height)
    33. End Sub
    34. Protected Overrides Sub OnPaint(e As PaintEventArgs)
    35. MyBase.OnPaint(e)
    36. If T.Rect.X < 0 Then T.Rect.X = 0
    37. If T.Rect.X > Width - T.Width Then T.Rect.X = Width - T.Width
    38. T.DrawThumb(e.Graphics, Check)
    39. End Sub
    40. Private Sub Toggler_SizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
    41. T = New Thumb(Width \ 2, Height)
    42. If Checked Then
    43. T.Rect.X = Width - T.Width
    44. End If
    45. End Sub
    46. Private Sub Toggler_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
    47. If e.Button = Windows.Forms.MouseButtons.Left AndAlso T.Rect.IntersectsWith(New Rectangle(e.Location.X, e.Location.Y, 1, 1)) Then
    48. Diff = e.Location.X - T.Rect.X
    49. IsMouseDown = True
    50. End If
    51. End Sub
    52. Private Sub Toggler_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
    53. If IsMouseDown Then
    54. T.Rect.X = e.Location.X - Diff
    55. Invalidate()
    56. End If
    57. End Sub
    58. Private Sub Toggler_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
    59. Checked = Check()
    60. IsMouseDown = False
    61. End Sub
    62. Private Function Check() As Boolean
    63. Select Case True
    64. Case Checked And T.Rect.X <= Width / 4
    65. Return False
    66. Case Checked And Not T.Rect.X <= Width / 4
    67. Return True
    68. Case Not Checked And T.Rect.X >= Width / 4
    69. Return True
    70. Case Not Checked And Not T.Rect.X >= Width / 4
    71. Return False
    72. Case Else
    73. Return Checked
    74. End Select
    75. End Function
    76. Private Class Thumb
    77. Private S As New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center}
    78. Private F As New Font("Microsoft Sans Serif", 10)
    79. Public Width As Integer
    80. Public Height As Integer
    81. Public Rect As Rectangle
    82. Sub New(width As Integer, height As Integer)
    83. Me.Width = width
    84. Me.Height = height
    85. Rect = New Rectangle(0, 0, width, height)
    86. End Sub
    87. Public Sub DrawThumb(g As Graphics, drawChecked As Boolean)
    88. If drawChecked Then
    89. g.FillRectangle(Brushes.Green, Rect)
    90. g.DrawString("I", F, Brushes.Black, Rect, S)
    91. Else
    92. g.FillRectangle(Brushes.Red, Rect)
    93. g.DrawString("O", F, Brushes.Black, Rect, S)
    94. End If
    95. End Sub
    96. End Class
    97. End Class

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Murdock“ ()

    Hey, das ist echt ne gute Basis!

    Danke schonmal für deine Mühe.
    Momentan sieht das Control so aus:


    Ich habe die Farben an dem Original Jelly Bean angepasst und eine (kleine) Optimierung bei der Zeichnung des Strings vorgenommen.
    Desweiteren habe ich das Größenverhältnis angepasst.

    Nun bin ich gerade dabei, den Thumb an allen Seiten um 2 Pixel zu schrumpfen:
    Auf der linken Seite müssen zwar auch 2 Pixel weg, jedoch muss der Thumb dann quasi den Anschlag schon haben, wenn links noch 2 Pixel übrig sind, siehe Original:


    ToDo:
    • Thumb verkleinern
    • Ecken des Thumbs abrunden


    Und ich habe gesehen, dass du deinen Beitrag bearbeitet hast.
    Kannst du mir sagen, was du im Code verändert hast?

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „TRiViUM“ ()

    Ich habe die Methode Toggler_SizeChanged mit

    VB.NET-Quellcode

    1. If Checked Then
    2. T.Rect.X = Width - T.Width
    3. End If

    erweitert, damit wenn Checked = True ist, der neue Thumb auch auf der richtigen Seite gemalt wird, wenn die Größe des Controls verändert wird.
    So müsste es passen, nur spicken wenn's net klappt ;) .
    Spoiler anzeigen

    VB.NET-Quellcode

    1. <System.ComponentModel.DefaultEvent("CheckedChanged")>
    2. Public Class Toggler
    3. Inherits Control
    4. Private T As Thumb
    5. Private Diff As Integer
    6. Private IsMouseDown As Boolean
    7. Public Event CheckedChanged(sender As Object)
    8. Private _checked As Boolean = False
    9. Public Property Checked As Boolean
    10. Get
    11. Return _checked
    12. End Get
    13. Set(value As Boolean)
    14. If value Then
    15. T.Rect.X = Width - T.Width
    16. Else
    17. T.Rect.X = 2
    18. End If
    19. If _checked <> value Then
    20. _checked = value
    21. RaiseEvent CheckedChanged(Me)
    22. End If
    23. Invalidate()
    24. End Set
    25. End Property
    26. Sub New()
    27. MyBase.New()
    28. SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.UserPaint Or ControlStyles.ResizeRedraw, True)
    29. BackColor = Color.Black
    30. Width = 80
    31. Height = 20
    32. T = New Thumb(Width \ 2, Height)
    33. End Sub
    34. Protected Overrides Sub OnPaint(e As PaintEventArgs)
    35. MyBase.OnPaint(e)
    36. If T.Rect.X < 2 Then T.Rect.X = 2
    37. If T.Rect.X > Width - T.Width Then T.Rect.X = Width - T.Width
    38. T.DrawThumb(e.Graphics, Check)
    39. End Sub
    40. Private Sub Toggler_SizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
    41. T = New Thumb(Width \ 2, Height)
    42. If Checked Then
    43. T.Rect.X = Width - T.Width
    44. End If
    45. End Sub
    46. Private Sub Toggler_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
    47. If e.Button = Windows.Forms.MouseButtons.Left AndAlso T.Rect.IntersectsWith(New Rectangle(e.Location.X, e.Location.Y, 1, 1)) Then
    48. Diff = e.Location.X - T.Rect.X
    49. IsMouseDown = True
    50. End If
    51. End Sub
    52. Private Sub Toggler_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
    53. If IsMouseDown Then
    54. T.Rect.X = e.Location.X - Diff
    55. Invalidate()
    56. End If
    57. End Sub
    58. Private Sub Toggler_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
    59. Checked = Check()
    60. IsMouseDown = False
    61. End Sub
    62. Private Function Check() As Boolean
    63. Select Case True
    64. Case Checked And T.Rect.X - 1 <= Width / 4
    65. Return False
    66. Case Checked And Not T.Rect.X - 1 <= Width / 4
    67. Return True
    68. Case Not Checked And T.Rect.X - 1 >= Width / 4
    69. Return True
    70. Case Not Checked And Not T.Rect.X - 1 >= Width / 4
    71. Return False
    72. Case Else
    73. Return Checked
    74. End Select
    75. End Function
    76. Private Class Thumb
    77. Private S As New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center}
    78. Private F As New Font("Microsoft Sans Serif", 10)
    79. Public Width As Integer
    80. Public Height As Integer
    81. Public Rect As Rectangle
    82. Sub New(width As Integer, height As Integer)
    83. Me.Width = width
    84. Me.Height = height
    85. Rect = New Rectangle(2, 2, width - 2, height - 4)
    86. End Sub
    87. Public Sub DrawThumb(g As Graphics, drawChecked As Boolean)
    88. If drawChecked Then
    89. g.FillRectangle(Brushes.Green, Rect)
    90. g.DrawString("I", F, Brushes.Black, Rect, S)
    91. Else
    92. g.FillRectangle(Brushes.Red, Rect)
    93. g.DrawString("O", F, Brushes.Black, Rect, S)
    94. End If
    95. End Sub
    96. End Class
    97. End Class

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Murdock“ ()

    Zu gütig der Herr :saint:
    Habe es bis hier hin geschafft:


    Unten müssen also noch die 2 Pixel weg.

    Ich habe viel Geduld :P


    Aber wenn ich versuch logisch nachzudenken, müsste ich das rectangle vom Thumb logischerweise schon verkleinern, bevor ich es fülle.

    Edit:
    Soweit-Sogut:

    Falls du denkst, die Schrift wäre zu klein bzw zu groß, lass es mich wissen :)
    ich weiß, dass man das alles selber ändern kann, aber ich würde gern ein sauberes, fertiges, und vor allem ein nah am original orientiertes Control basteln :)

    ToDo:
    •Die Ecken von dem Thumb Rectangle abrunden...

    Fällt dir noch was ein?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TRiViUM“ ()

    Sicher hab ich eine Idee. Anstatt das Rectangle zu malen, nimmst einen GraphicsPath, den malste mit Graphics.FillPath. So geht das, musst die Funktion GetRoundedPath ein wenig anpassen, damit es an den Ecken auch passt ;) .
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Class Thumb
    2. Private S As New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center}
    3. Private F As New Font("Microsoft Sans Serif", 10)
    4. Public Width As Integer
    5. Public Height As Integer
    6. Public Rect As Rectangle
    7. Sub New(width As Integer, height As Integer)
    8. Me.Width = width
    9. Me.Height = height
    10. Rect = New Rectangle(2, 2, width - 2, height - 4)
    11. End Sub
    12. Public Sub DrawThumb(g As Graphics, drawChecked As Boolean)
    13. Using GP As GraphicsPath = New GraphicsPath
    14. GetRoundedPath(Rect, 1, GP)
    15. If drawChecked Then
    16. g.FillPath(Brushes.Green, GP)
    17. g.DrawString("I", F, Brushes.Black, Rect, S)
    18. Else
    19. g.FillPath(Brushes.Red, GP)
    20. g.DrawString("O", F, Brushes.Black, Rect, S)
    21. End If
    22. End Using
    23. End Sub
    24. Private Function GetRoundedPath(re As Rectangle, r As Integer, GP As GraphicsPath) As GraphicsPath
    25. GP.AddLine(re.X + r, re.Y, re.X + re.Width - r, re.Y)
    26. GP.AddArc(re.X + re.Width - r, re.Y, r, r, 270, 90)
    27. GP.AddLine(re.X + re.Width, re.Y + r, re.X + re.Width, re.Y + re.Height - r)
    28. GP.AddArc(re.X + re.Width - r, re.Y + re.Height - r, r, r, 0, 90)
    29. GP.AddLine(re.X + re.Width - r, re.Y + re.Height, re.X + r, re.Y + re.Height)
    30. GP.AddArc(re.X, re.Y + re.Height - r, r, r, 90, 90)
    31. GP.AddLine(re.X, re.Y + re.Height - r, re.X, re.Y + r)
    32. GP.AddArc(re.X, re.Y, r, r, 180, 90)
    33. GP.CloseFigure()
    34. Return GP
    35. End Function
    36. End Class
    Dann sollte es abgerundet so aussehen:


    Dann die letzten Feinschliffe:
    Im Original ist oben auf dem Schieber ein heller Glanz, also nur die erste Pixelreihe.
    Zeichne ich dann einfach ein Strich und versuche ihn mit Antialiasing weich zu zeichnen?

    Und, Kann ich die jetzt abgerundeten Kanten vom Thumb auch weich zeichnen? hab zwar ein wenig experimentiert, aber immer schlechtere Ergebnisse bekommen als auf dem Bild zu sehen.

    Und, kann man den String bzw Text auf dem Thumb weichzeichnen?
    habe zwar ​SmoothingMode.HighQuality aber bringt nix..
    Für LiniarGradientBrushes, isses ein bischen zu schmal(1px). Evtl. ein PathGradientBrush, ich würde das auch mit einer Linie machen, allerdings mit Transparenz. Ein Graphics-Object hat mehrere Properties welche du einfach mal durchtesten muss, so hab ich schon ein relativ gutes Ergebniss. Ganz so fein wie auf einem Android wird das in WinForms mit GDI nicht machbar sein, da das ganz unterschiedlich Gerendert wird. Manchmal nehm ich auch gern Bitmaps für so kleine Sachen, damit krieg ich das etwas feiner hin.

    VB.NET-Quellcode

    1. Public Sub DrawThumb(g As Graphics, drawChecked As Boolean)
    2. Using GP As GraphicsPath = New GraphicsPath
    3. GetRoundedPath(Rect, 2, GP)
    4. g.TextContrast = 0 '0 bis 12
    5. g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
    6. g.InterpolationMode = InterpolationMode.HighQualityBicubic
    7. g.CompositingQuality = CompositingQuality.GammaCorrected
    8. g.SmoothingMode = SmoothingMode.HighQuality
    9. Using SB As New SolidBrush(Color.FromArgb(40, 255, 255, 255))
    10. Using p As New Pen(SB, 1)
    11. If drawChecked Then
    12. g.FillPath(Brushes.Green, GP)
    13. g.DrawString("ON", F, Brushes.Black, Rect, S)
    14. Else
    15. g.FillPath(Brushes.Red, GP)
    16. g.DrawString("OFF", F, Brushes.Black, Rect, S)
    17. End If
    18. g.DrawLine(p, Rect.X, 2, Rect.X + Rect.Width - 2, 2)
    19. End Using
    20. End Using
    21. End Using
    22. End Sub

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Murdock“ ()

    Sehr Cool!
    Habe es hier und da ein wenig angepasst/ optimiert.
    Hinzugekommen ist u.A. die Funktion, dass beim Klicken auf das Control das Control umgeschaltet wird.

    Das Ergebnis? Ein fertiges Android 4.1+ Jelly Bean - Toggle Switch Control!


    Vielen Dank @Murdock für die Basis des Toggle-Controls :saint:

    Im laufe der Woche werde ich noch versuchen die Samsung Toggle Switch zu bauen.
    Alles weitere kommt dann in diesen Thread!
    Dateien

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „TRiViUM“ ()