Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Slider for #2435 #3152

Open
wants to merge 2 commits into
base: ucr
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 50 additions & 8 deletions appinventor/components-ios/src/Slider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ public class Slider: ViewComponent, AbstractMethodsForViewComponent {
private var _view: UISlider
private var _minValue: Float32 = kSliderMinValue
private var _maxValue: Float32 = kSliderMaxValue
private var _scaleGraduationInt: Int32 = 100
private var _scaleGraduation: Float32 = 100.0
private var _notice: Bool = true
private var _thumbPosition: Float32 = kSliderThumbValue
private var _leftColor: UIColor = UIColor.orange
private var _rightColor: UIColor = UIColor.gray
Expand All @@ -24,6 +27,7 @@ public class Slider: ViewComponent, AbstractMethodsForViewComponent {
ThumbPosition = kSliderThumbValue
MinValue = kSliderMinValue
MaxValue = kSliderMaxValue
ScaleGraduation = _scaleGraduationInt;
Width = 50
}

Expand All @@ -32,10 +36,12 @@ public class Slider: ViewComponent, AbstractMethodsForViewComponent {
_view.translatesAutoresizingMaskIntoConstraints = false
_view.minimumTrackTintColor = _leftColor
_view.maximumTrackTintColor = _rightColor
_view.maximumValue = 100.0
_view.maximumValue = _scaleGraduation
_view.minimumValue = 0.0
_view.isEnabled = true
_view.addTarget(self, action: #selector(self.positionChanged(sender:)), for: .valueChanged)
_view.addTarget(self, action: #selector(self.handleTouchDown), for: .touchDown)
_view.addTarget(self, action: #selector(self.handleTouchUp), for: [.touchUpInside, .touchUpOutside, .touchCancel])
}

public override var view: UIView {
Expand Down Expand Up @@ -70,7 +76,7 @@ public class Slider: ViewComponent, AbstractMethodsForViewComponent {
set(value) {
_minValue = value
_maxValue = max(value, _maxValue)
ThumbPosition = (_maxValue + _minValue) / 2.0
_thumbPosition = ((_maxValue - _minValue) * _view.value / _scaleGraduation) + _minValue;
}
}

Expand All @@ -81,7 +87,25 @@ public class Slider: ViewComponent, AbstractMethodsForViewComponent {
set(value) {
_maxValue = value
_minValue = min(value, _minValue)
ThumbPosition = (_minValue + _maxValue) / 2.0
_thumbPosition = ((_maxValue - _minValue) * _view.value / _scaleGraduation) + _minValue;
}
}

@objc public var ScaleGraduation: Int32 {
get {
return Int(_scaleGraduationInt)
}
set(value) {
_scaleGraduationInt = value
_scaleGraduation = Float(value)
let oldPosition: Float = _thumbPosition
// We set the notice flag to false so that the user is not informed in any way about the change of this property
_notice = false
_view.maximumValue = _scaleGraduation
// restore the original position
_thumbPosition = oldPosition
setSliderPosition()
_notice = true;
}
}

Expand All @@ -106,19 +130,37 @@ public class Slider: ViewComponent, AbstractMethodsForViewComponent {
}

// Set the slider position based on _minValue, _maxValue, and _thumbPosition
// Slider position is a float in the range [0,100] and is determined by _minValue,
// Slider position is a float in the range [0,_scaleGraduation] and is determined by _minValue,
// _maxValue and _thumbPosition
private func setSliderPosition() {
let thumbPosition: Float = (_thumbPosition - _minValue) / (_maxValue - _minValue) * 100.0
thumbPosition.isNaN ? _view.setValue(50.0, animated: true) : _view.setValue(thumbPosition, animated: true)
let thumbPosition: Float = (_thumbPosition - _minValue) / (_maxValue - _minValue) * _scaleGraduation
thumbPosition.isNaN ? _view.setValue(50.0, animated: _notice) : _view.setValue(thumbPosition, animated: _notice)
}

@objc func positionChanged(sender: UISlider) {
_thumbPosition = (_maxValue - _minValue) * sender.value / 100 + _minValue
PositionChanged(_thumbPosition)
if (_notice) {
_thumbPosition = (_maxValue - _minValue) * sender.value / _scaleGraduation + _minValue
PositionChanged(_thumbPosition)
}
}

@objc func handleTouchDown() {
TouchDown();
}

@objc func handleTouchUp() {
TouchUp();
}

@objc open func PositionChanged(_ thumbPosition: Float) {
EventDispatcher.dispatchEvent(of: self, called: "PositionChanged", arguments: thumbPosition as NSNumber)
}

@objc open func TouchDown() {
EventDispatcher.dispatchEvent(of: self, called: "TouchDown")
}

@objc open func TouchUp() {
EventDispatcher.dispatchEvent(of: self, called: "TouchUp")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public class Slider extends AndroidViewComponent implements SeekBar.OnSeekBarCha

private final SeekBar seekbar;

private int scaleGraduation;
private boolean notice = true;
// slider mix, max, and thumb positions
private float minValue;
private float maxValue;
Expand Down Expand Up @@ -122,22 +124,23 @@ public Slider(ComponentContainer container) {
maxValue = Component.SLIDER_MAX_VALUE;
thumbPosition = Component.SLIDER_THUMB_VALUE;
thumbEnabled = true;
scaleGraduation = 100;

seekbar.setOnSeekBarChangeListener(this);

//NOTE(kashi01): The boundaries for Seekbar are between 0-100 and there is no lower-limit that could
// be set. We keep the SeekBar effectively at [0-100] and calculate thumb position within that
// range.
seekbar.setMax(100);
// We set the maximum range of the slider to scaleGraduation,
// obtaining the slider precision exactly as we want.

seekbar.setMax(scaleGraduation);

// Based on given minValue, maxValue, and thumbPosition, determine where the seekbar
// thumb position would be within normal SeekBar 0-100 range
// !!! check this. maybe don't want to pass the args???
// thumb position would be within normal SeekBar 0 - scaleGraduation range

setSeekbarPosition();

if (DEBUG) {
Log.d(LOG_TAG, "Slider initial min, max, thumb values are: " +
MinValue() + "/" + MaxValue() + "/" + ThumbPosition());
MinValue() + "/" + MaxValue() + "/" + ThumbPosition() + "/" + ScaleGraduation());
}

if (DEBUG) {
Expand Down Expand Up @@ -171,24 +174,27 @@ private void setSliderColors() {
}
} else {
LayerDrawable fullBar = (LayerDrawable) seekbar.getProgressDrawable();
fullBar.setColorFilter(rightColor,PorterDuff.Mode.SRC);
fullBar.setColorFilter(rightColor, PorterDuff.Mode.SRC);
fullBar.findDrawableByLayerId(R.id.progress).setColorFilter(leftColor, PorterDuff.Mode.SRC);
}
}

// Set the seekbar position based on minValue, maxValue, and thumbPosition
// seekbar position is an integer in the range [0,100] and is determined by MinValue,
// seekbar position is an integer in the range [0,scaleGraduation] and is determined by MinValue,
// MaxValue and ThumbPosition
private void setSeekbarPosition() {
float seekbarPosition = ((thumbPosition - minValue) / (maxValue - minValue)) * 100;
float seekbarPosition = ((thumbPosition - minValue) / (maxValue - minValue)) * scaleGraduation;

if (DEBUG) {
Log.d(LOG_TAG, "Trying to recalculate seekbar position "
+ minValue + "/" + maxValue + "/" + thumbPosition + "/" + seekbarPosition);
}

// Set the thumb position on the seekbar
seekbar.setProgress((int) seekbarPosition);
// I've enabled animations when changing progress programmatically,
// as it does in the iOS version.
// However, animation is disabled when setting the ScaleGraduation property.
seekbar.setProgress((int) seekbarPosition, notice);
}

/**
Expand Down Expand Up @@ -249,7 +255,6 @@ public void ThumbPosition(float position) {
if (DEBUG) {
Log.d(LOG_TAG, "ThumbPosition is set to: " + thumbPosition);}
setSeekbarPosition();
PositionChanged(thumbPosition);
}

/**
Expand All @@ -268,17 +273,12 @@ public float ThumbPosition() {
/**
* Sets the minimum value of slider. If the new minimum is greater than the
* current maximum, then minimum and maximum will both be set to this value.
* Setting `MinValue` resets the thumb position to halfway between `MinValue`
* and {@link #MaxValue()} and signals the {@link #PositionChanged(float)}`
* event.
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_FLOAT,
defaultValue = Component.SLIDER_MIN_VALUE + "")
@SimpleProperty(description = "Sets the minimum value of slider. Changing the minimum value " +
"also resets Thumbposition to be halfway between the (new) minimum and the maximum. " +
@SimpleProperty(description = "Sets the minimum value of slider. " +
"If the new minimum is greater than the current maximum, then minimum and maximum will " +
"both be set to this value. Setting MinValue resets the thumb position to halfway " +
"between MinValue and MaxValue and signals the PositionChanged event.",
"both be set to this value.",
userVisible = true)
public void MinValue(float value) {
minValue = value;
Expand All @@ -288,7 +288,7 @@ public void MinValue(float value) {
if (DEBUG) {
Log.d(LOG_TAG, "Min value is set to: " + value);
}
ThumbPosition ((minValue + maxValue) / 2.0f);
thumbPosition = ((maxValue - minValue) * (float) seekbar.getProgress() / scaleGraduation) + minValue;
}


Expand All @@ -307,16 +307,12 @@ public float MinValue() {
/**
* Sets the maximum value of slider. If the new maximum is less than the
* current minimum, then minimum and maximum will both be set to this value.
* Setting `MaxValue` resets the thumb position to halfway between {@link #MinValue()}
* and `MaxValue` and signals the {@link #PositionChanged(float)}` event.
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_FLOAT,
defaultValue = Component.SLIDER_MAX_VALUE + "")
@SimpleProperty(description = "Sets the maximum value of slider. Changing the maximum value " +
"also resets Thumbposition to be halfway between the minimum and the (new) maximum. " +
@SimpleProperty(description = "Sets the maximum value of slider. " +
"If the new maximum is less than the current minimum, then minimum and maximum will both " +
"be set to this value. Setting MaxValue resets the thumb position to halfway " +
"between MinValue and MaxValue and signals the PositionChanged event.",
"be set to this value. ",
userVisible = true)
public void MaxValue(float value) {
maxValue = value;
Expand All @@ -325,7 +321,7 @@ public void MaxValue(float value) {
if (DEBUG) {
Log.d (LOG_TAG, "Max value is set to: " + value);
}
ThumbPosition ((minValue + maxValue) / 2.0f);
thumbPosition = ((maxValue - minValue) * (float) seekbar.getProgress() / scaleGraduation) + minValue;
}

/**
Expand All @@ -340,6 +336,35 @@ public float MaxValue() {
return maxValue;
}

/**
* Set the slider scale graduation. This allows you to set the number of points on the slider scale.
* Combined with MinValue and MaxValue, it allows you to get the slider precision that you want,
* e.g. MinValue = 0, MaxValue = 150, ScaleGraduation = 1000. The slider will change position every 0.15.
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_NON_NEGATIVE_INTEGER,
defaultValue = "100")
@SimpleProperty(description = "Set the slider scale graduation. This allows you to set the number of points " +
"on the slider scale. Combined with MinValue and MaxValue, it allows you to get the slider precision " +
"that you want, e.g. MinValue = 0, MaxValue = 150, ScaleGraduation = 1000, the slider will change " +
"position every 0.15.", userVisible = true)
public void ScaleGraduation(int value) {
scaleGraduation = value;
// We save the position to restore it after setting the properties
float oldPosition = thumbPosition;
// We set the notice flag to false so that the user is not informed in any way about the change of this property
notice = false;
seekbar.setMax(value);
// restore the original position
thumbPosition = oldPosition;
setSeekbarPosition();
notice = true;
}

@SimpleProperty(category = PropertyCategory.APPEARANCE,
description = "Returns the slider increase.", userVisible = true)
public int ScaleGraduation() {
return scaleGraduation;
}

/**
* Returns the color of the slider bar to the left of the thumb, as an alpha-red-green-blue
Expand Down Expand Up @@ -412,20 +437,23 @@ public View getView() {

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//progress has been changed. Set the sliderThumbPosition and then trigger the event
// progress has been changed. Set the sliderThumbPosition and then trigger the event
// Now convert this progress value (which is between 0-scaleGraduation), back to a value between the
// range that user has set within minValue, maxValue

//Now convert this progress value (which is between 0-100), back to a value between the
//range that user has set within minValue, maxValue
thumbPosition = ((maxValue - minValue) * (float) progress / 100)
+ minValue;
// We check the notice flag so as not to trigger the event when we change the ScaleGraduation property.
if (notice) {
thumbPosition = ((maxValue - minValue) * (float) progress / scaleGraduation) + minValue;

if (DEBUG) {
Log.d(LOG_TAG, "onProgressChanged progress value [0-100]: " + progress
+ ", reporting to user as: " + thumbPosition);
}
if (DEBUG) {
Log.d(LOG_TAG, "onProgressChanged progress value [0-scaleGraduation]: " + progress
+ ", reporting to user as: " + thumbPosition);
}

//Trigger the event, reporting this new value
PositionChanged(thumbPosition);
// Trigger the event, reporting this new value

PositionChanged(thumbPosition);
}
}

/**
Expand All @@ -436,14 +464,30 @@ public void PositionChanged(float thumbPosition) {
EventDispatcher.dispatchEvent(this, "PositionChanged", thumbPosition);
}

/**
* Indicates that the user has started a touch gesture.
*/
@SimpleEvent
public void TouchDown() {
EventDispatcher.dispatchEvent(this, "TouchDown");
}

/**
* Indicates that the user has finished a touch gesture.
*/
@SimpleEvent
public void TouchUp() {
EventDispatcher.dispatchEvent(this, "TouchUp");
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
TouchDown();
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
TouchUp();
}

/**
Expand Down