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

feat(android): add Ti.UI.ButtonBar #12389

Merged
merged 6 commits into from
Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Widget.Titanium.OutlinedButton.IconOnly" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="iconGravity">textStart</item>
<item name="iconPadding">0dp</item>
<item name="android:insetTop">0dp</item>
<item name="android:insetBottom">0dp</item>
<item name="android:paddingLeft">12dp</item>
<item name="android:paddingRight">12dp</item>
<item name="android:minWidth">48dp</item>
<item name="android:minHeight">48dp</item>
</style>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2021 by Axway, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
package ti.modules.titanium.ui;

import android.app.Activity;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.view.TiUIView;
import ti.modules.titanium.ui.widget.TiUIButtonBar;

@Kroll.proxy(creatableInModule = UIModule.class, propertyAccessors = {
TiC.PROPERTY_LABELS,
})
public class ButtonBarProxy extends TiViewProxy
{
@Override
public TiUIView createView(Activity activity)
{
return new TiUIButtonBar(this);
}

@Override
public String getApiName()
{
return "Ti.UI.ButtonBar";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2021 by Axway, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
package ti.modules.titanium.ui.widget;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.appcompat.view.ContextThemeWrapper;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.button.MaterialButtonToggleGroup;
import java.util.HashMap;
import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollProxy;
import org.appcelerator.titanium.R;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.util.TiUIHelper;
import org.appcelerator.titanium.view.TiUIView;

public class TiUIButtonBar extends TiUIView
{
private static final String TAG = "TiUIButtonBar";

public TiUIButtonBar(TiViewProxy proxy)
{
super(proxy);

// Create view group used to host buttons.
MaterialButtonToggleGroup buttonGroup = new MaterialButtonToggleGroup(proxy.getActivity());
buttonGroup.setSelectionRequired(false);
buttonGroup.setSingleSelection(false);
buttonGroup.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(
View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom)
{
TiUIHelper.firePostLayoutEvent(getProxy());
}
});
setNativeView(buttonGroup);
}

@Override
public void processProperties(KrollDict properties)
{
// Validate.
if (properties == null) {
return;
}

// Apply given properties to view.
if (properties.containsKey(TiC.PROPERTY_LABELS)) {
processLabels(properties.get(TiC.PROPERTY_LABELS));
}

// Let base class handle all other view property settings.
super.processProperties(properties);
}

@Override
public void propertyChanged(String key, Object oldValue, Object newValue, KrollProxy proxy)
{
// Validate.
if (key == null) {
return;
}

// Handle property change.
if (key.equals(TiC.PROPERTY_LABELS)) {
processLabels(newValue);
} else {
super.propertyChanged(key, oldValue, newValue, proxy);
}
}

private void processLabels(Object labels)
{
// Do not continue if proxy has been released.
if (this.proxy == null) {
return;
}

// Fetch the button group view.
MaterialButtonToggleGroup buttonGroup = getButtonGroup();
if (buttonGroup == null) {
return;
}

// Clear the previously assigned buttons.
buttonGroup.removeAllViews();

// Fetch "labels" property and validate it.
if ((labels == null) || !labels.getClass().isArray()) {
return;
}
Object[] objectArray = (Object[]) labels;
if (objectArray.length <= 0) {
return;
}

// Process the labels object.
if (objectArray[0] instanceof String) {
// We were given an array of button titles.
for (Object title : objectArray) {
addButton(TiConvert.toString(title, ""), null, null, true);
}
} else if (objectArray[0] instanceof HashMap) {
// We were given an array of Titanium "BarItemType" dictionaries.
for (Object nextObject : objectArray) {
// Make sure next element is a dictionary.
if ((nextObject instanceof HashMap) == false) {
continue;
}
HashMap hashMap = (HashMap) nextObject;

// Fetch the optional "title" property.
String title = TiConvert.toString(hashMap.get(TiC.PROPERTY_TITLE), "");

// Fetch the optional "accessibilityLabel" property.
String accessibilityLabel = TiConvert.toString(hashMap.get(TiC.PROPERTY_ACCESSIBILITY_LABEL), null);

// Fetch the optional "image" property and load it as a drawable.
Drawable imageDrawable = null;
Object imageObject = hashMap.get(TiC.PROPERTY_IMAGE);
if (imageObject != null) {
imageDrawable = TiUIHelper.getResourceDrawable(imageObject);
}

// Fetch the optional "enabled" flag.
boolean isEnabled = TiConvert.toBoolean(hashMap.get(TiC.PROPERTY_ENABLED), true);

// Add the button.
addButton(title, accessibilityLabel, imageDrawable, isEnabled);
}
}
}

private void addButton(String title, String accessibilityLabel, Drawable imageDrawable, boolean isEnabled)
{
// Fetch the button group view.
MaterialButtonToggleGroup buttonGroup = getButtonGroup();
if (buttonGroup == null) {
return;
}

// Title must be non-null.
if (title == null) {
title = "";
}

// Create a button with given settings and add it to view group.
Context context = buttonGroup.getContext();
int attributeId = R.attr.materialButtonOutlinedStyle;
if (title.isEmpty() && (imageDrawable != null)) {
context = new ContextThemeWrapper(context, R.style.Widget_Titanium_OutlinedButton_IconOnly);
attributeId = R.attr.materialButtonToggleGroupStyle;
}
MaterialButton button = new MaterialButton(context, null, attributeId);
button.setText(title);
if ((accessibilityLabel != null) && !accessibilityLabel.isEmpty()) {
button.setContentDescription(accessibilityLabel);
}
if (imageDrawable != null) {
button.setIcon(imageDrawable);
}
buttonGroup.addView(button);
button.setCheckable(false);
button.setEnabled(isEnabled);
button.setOnClickListener((view) -> {
if (this.proxy == null) {
return;
}
for (int index = 0; index < buttonGroup.getChildCount(); index++) {
View childView = buttonGroup.getChildAt(index);
if (childView == view) {
KrollDict data = new KrollDict();
data.put(TiC.PROPERTY_INDEX, index);
this.proxy.fireEvent(TiC.EVENT_CLICK, data);
return;
}
}
});
}

private MaterialButtonToggleGroup getButtonGroup()
{
View view = getNativeView();
if (view instanceof MaterialButtonToggleGroup) {
return (MaterialButtonToggleGroup) view;
}
return null;
}
}
45 changes: 16 additions & 29 deletions apidoc/Titanium/UI/ButtonBar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,18 @@
name: Titanium.UI.ButtonBar
summary: An iOS button bar component.
description: |
The button bar is a set of buttons joined into a single control. Each button in a
button bar can have a text label or an icon, but not both.
The button bar is a set of buttons joined into a single control.
On iOS, you can set up the buttons with either a title or image, but not both.
On Android, you can set up the buttons with a title, image, or both.

Use the <Titanium.UI.createButtonBar> method or **`<ButtonBar>`** Alloy element to create a button bar.

The [TabbedBar](Titanium.UI.iOS.TabbedBar) control is a button bar where the
last selected button mantains a pressed or selected state. The following discussion
applies to both button bar and tabbed bar.

The buttons share a common style, defined by the `style` property. This can be
set to one of the constants defined in
[Titanium.UI.iOS.SystemButtonStyle](Titanium.UI.iOS.SystemButtonStyle):

* `PLAIN`. Default style for `ButtonBar` and `TabbedBar`.
* `BORDERED`. Creates a bar like the `PLAIN` bar, but with a heavier border.

Note that you cannot style individual buttons in a button bar. If you want to give a
distinct visual style to individual buttons, to use an icon and text on the same button,
or to use a button-bar type component on a platform other than iOS, you can use a set
of individual [Button](Titanium.UI.Button) controls wrapped in a
[View](Titanium.UI.View) to create the appearance of a button bar.
extends: Titanium.UI.View
since: "0.8"
platforms: [iphone, ipad, macos]
since: {android: "10.0.0", iphone: "0.8", ipad: "0.8", macos: "9.2.0"}
platforms: [android, iphone, ipad, macos]
excludes:
events: [ 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'dblclick',
'doubletap', 'longclick', 'singletap', 'swipe', 'twofingertap' ]
Expand All @@ -37,7 +25,7 @@ events:
summary: Fired when a button is clicked.
properties:
- name: index
summary: Index of the clicked button.
summary: Index of the clicked button.
type: Number
properties:
- name: index
Expand All @@ -60,7 +48,7 @@ properties:

``` xml
<Alloy>
<ButtonBar platform="ios">
<ButtonBar>
<Labels>
<!-- Specify text with node text or "title" attribute. -->
<Label>button 1</Label>
Expand Down Expand Up @@ -106,15 +94,15 @@ examples:
- title: Simple 3 button button bar
example: |
``` js
var bb1 = Titanium.UI.createButtonBar({
labels:['One', 'Two', 'Three'],
backgroundColor:'#336699',
top:50,
style:Titanium.UI.iOS.SystemButtonStyle.PLAIN,
height:25,
width:200
const win = Ti.UI.createWindow();
const buttonBar = Titanium.UI.createButtonBar({
labels:['One', 'Two', 'Three']
});
buttonBar.addEventListener('click', (e) => {
console.log(`Clicked on button index: ${e.index}`);
});
win.add(bb1);
win.add(buttonBar);
win.open();
```

- title: Alloy XML Markup
Expand All @@ -124,7 +112,7 @@ examples:
``` xml
<Alloy>
<Window id="win">
<ButtonBar id="bb1" platform="ios" backgroundColor="#369" top="50" height="25" width="200">
<ButtonBar id="buttonBar">
<!-- The Labels tag sets the ButtonBar.labels property -->
<Labels>
<!-- Specify text with node text or the title attribute. -->
Expand All @@ -133,7 +121,6 @@ examples:
<Label>Two</Label>
<Label>Three</Label>
</Labels>
<!-- Place additional views for the ButtonBar here. -->
</ButtonBar>
</Window>
</Alloy>
Expand Down
1 change: 1 addition & 0 deletions tests/Resources/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ function loadTests() {
}
require('./ti.ui.attributedstring.test');
require('./ti.ui.button.test');
require('./ti.ui.buttonbar.test');
require('./ti.ui.clipboard.test');
require('./ti.ui.constants.test');
require('./ti.ui.emaildialog.test');
Expand Down
Loading