Skip to content
This repository was archived by the owner on May 1, 2020. It is now read-only.

Commit

Permalink
Programatically generate configurator view
Browse files Browse the repository at this point in the history
This removes the dependency on resources making it possible to put
the entire project into a jar file for easier integration.
  • Loading branch information
willbailey committed Jan 30, 2014
1 parent 88be135 commit 0a5b504
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 160 deletions.
6 changes: 2 additions & 4 deletions BUCK
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# A special build that includes rebound-android but not the resources so that a jar file can be
# created for distribution to users who do not use the gradle aar and don't need the utils like
# SpringConfiguratorView.
# A special build that depends on rebound-android:src and packages into a jar file for distribution.
java_binary(
name = 'rebound',
deps = ['//rebound-android:src-no-res'],
deps = ['//rebound-android:src'],
visibility = ['PUBLIC'],
)
1 change: 0 additions & 1 deletion bump.txt

This file was deleted.

24 changes: 1 addition & 23 deletions rebound-android/BUCK
Original file line number Diff line number Diff line change
@@ -1,29 +1,7 @@
android_resource(
name = 'res',
res = 'src/main/res',
package = 'com.facebook.rebound',
visibility = ['//rebound-android:src'],
)

android_library(
name = 'src',
srcs = glob(['src/main/java/**/*.java']),
deps = [
'//rebound-core:src',
'//rebound-android:res',
],
visibility = ['PUBLIC'],
)

android_library(
name = 'src-no-res',
srcs = glob(
['src/main/java/**/*.java'],
excludes = ['src/main/java/com/facebook/rebound/ui/*'],
),
deps = [
'//rebound-core:src',
],
deps = ['//rebound-core:src'],
visibility = ['PUBLIC'],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,26 @@

package com.facebook.rebound.ui;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TableLayout;
import android.widget.TextView;

import com.facebook.rebound.R;
import com.facebook.rebound.Spring;
import com.facebook.rebound.SpringConfig;
import com.facebook.rebound.SpringConfigRegistry;
Expand All @@ -36,29 +41,29 @@
import java.util.List;
import java.util.Map;

import static com.facebook.rebound.ui.Util.*;

/**
* The SpringConfiguratorView provides a reusable view for live-editing all registered springs
* within an Application. Each registered Spring can be accessed by its id and its tension and
* friction properties can be edited while the user tests the effected UI live.
*/
public class SpringConfiguratorView extends FrameLayout {

private static final String SPRING_CONFIG_NAME = "spring configurator revealer";
private static final int MAX_SEEKBAR_VAL = 100000;
private static final float MIN_TENSION = 0;
private static final float MAX_TENSION = 500;
private static final float MIN_FRICTION = 0;
private static final float MAX_FRICTION = 100;
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.#");

private final SpringSystem springSystem;
private final ArrayAdapter<String> springArrayAdapter;
private final SpinnerAdapter spinnerAdapter;
private final List<SpringConfig> mSpringConfigs = new ArrayList<SpringConfig>();
private final Spring mRevealerSpring;
private final float mStashPx;
private final float mRevealPx;
private final RevealerSpringListener mRevealerSpringListener;
private final SpringConfigRegistry springConfigRegistry;
private final int mTextColor = Color.argb(255, 225, 225, 225);
private SeekBar mTensionSeekBar;
private SeekBar mFrictionSeekBar;
private Spinner mSpringSelectorSpinner;
Expand All @@ -74,51 +79,138 @@ public SpringConfiguratorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public SpringConfiguratorView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

springSystem = SpringSystem.create();
SpringSystem springSystem = SpringSystem.create();
springConfigRegistry = SpringConfigRegistry.getInstance();
springArrayAdapter = new ArrayAdapter<String>(getContext(), R.layout.spring_text);
spinnerAdapter = new SpinnerAdapter(context);

mRevealPx = getResources().getDimensionPixelOffset(R.dimen.spring_configurator_reveal_px);
mStashPx = getResources().getDimensionPixelOffset(R.dimen.spring_configurator_stash_px);
Resources resources = getResources();
mRevealPx = dpToPx(40, resources);
mStashPx = dpToPx(280, resources);

mRevealerSpring = springSystem.createSpring();
mRevealerSpringListener = new RevealerSpringListener();
SpringListener revealerSpringListener = new RevealerSpringListener();
mRevealerSpring
.setCurrentValue(1)
.setEndValue(1)
.addListener(mRevealerSpringListener);

LayoutInflater inflater = LayoutInflater.from(context);
RelativeLayout content =
(RelativeLayout) inflater.inflate(R.layout.spring_configurator_view, this, false);
addView(content);
.addListener(revealerSpringListener);

View nub = findViewById(R.id.nub);
nub.setOnTouchListener(new OnNubTouchListener());
addView(generateHierarchy(context));

SeekbarListener seekbarListener = new SeekbarListener();

mTensionSeekBar = (SeekBar) findViewById(R.id.tension_seekbar);
mTensionSeekBar.setMax(MAX_SEEKBAR_VAL);
mTensionSeekBar.setOnSeekBarChangeListener(seekbarListener);
mTensionLabel = (TextView) findViewById(R.id.tension_label);

mFrictionSeekBar = (SeekBar) findViewById(R.id.friction_seekbar);
mFrictionSeekBar.setMax(MAX_SEEKBAR_VAL);
mFrictionSeekBar.setOnSeekBarChangeListener(seekbarListener);
mFrictionLabel = (TextView) findViewById(R.id.friction_label);

mSpringSelectorSpinner = (Spinner) findViewById(R.id.spring_selector_spinner);
mSpringSelectorSpinner.setAdapter(springArrayAdapter);
mSpringSelectorSpinner.setAdapter(spinnerAdapter);
mSpringSelectorSpinner.setOnItemSelectedListener(new SpringSelectedListener());
refreshSpringConfigurations();

this.setTranslationY(mStashPx);
}

/**
* Programmatically build up the view hierarchy to avoid the need for resources.
* @return View hierarchy
*/
private View generateHierarchy(Context context) {
Resources resources = getResources();

FrameLayout.LayoutParams params;
int fivePx = dpToPx(5, resources);
int tenPx = dpToPx(10, resources);
int twentyPx = dpToPx(20, resources);
TableLayout.LayoutParams tableLayoutParams = new TableLayout.LayoutParams(
0,
ViewGroup.LayoutParams.WRAP_CONTENT,
1f);
tableLayoutParams.setMargins(0, 0, fivePx, 0);
LinearLayout seekWrapper;

FrameLayout root = new FrameLayout(context);
params = createLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpToPx(300, resources));
root.setLayoutParams(params);

FrameLayout container = new FrameLayout(context);
params = createMatchParams();
params.setMargins(0, twentyPx, 0, 0);
container.setLayoutParams(params);
container.setBackgroundColor(Color.argb(100, 0, 0, 0));
root.addView(container);

mSpringSelectorSpinner = new Spinner(context, Spinner.MODE_DIALOG);
params = createMatchWrapParams();
params.gravity = Gravity.TOP;
params.setMargins(tenPx, tenPx, tenPx, 0);
mSpringSelectorSpinner.setLayoutParams(params);
container.addView(mSpringSelectorSpinner);

LinearLayout linearLayout = new LinearLayout(context);
params = createMatchWrapParams();
params.setMargins(0, 0, 0, dpToPx(80, resources));
params.gravity = Gravity.BOTTOM;
linearLayout.setLayoutParams(params);
linearLayout.setOrientation(LinearLayout.VERTICAL);
container.addView(linearLayout);

seekWrapper = new LinearLayout(context);
params = createMatchWrapParams();
params.setMargins(tenPx, tenPx, tenPx, twentyPx);
seekWrapper.setPadding(tenPx, tenPx, tenPx, tenPx);
seekWrapper.setLayoutParams(params);
seekWrapper.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.addView(seekWrapper);

mTensionSeekBar = new SeekBar(context);
mTensionSeekBar.setLayoutParams(tableLayoutParams);
seekWrapper.addView(mTensionSeekBar);

mTensionLabel = new TextView(getContext());
mTensionLabel.setTextColor(mTextColor);
params = createLayoutParams(
dpToPx(50, resources),
ViewGroup.LayoutParams.MATCH_PARENT);
mTensionLabel.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
mTensionLabel.setLayoutParams(params);
mTensionLabel.setMaxLines(1);
seekWrapper.addView(mTensionLabel);

seekWrapper = new LinearLayout(context);
params = createMatchWrapParams();
params.setMargins(tenPx, tenPx, tenPx, twentyPx);
seekWrapper.setPadding(tenPx, tenPx, tenPx, tenPx);
seekWrapper.setLayoutParams(params);
seekWrapper.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.addView(seekWrapper);

mFrictionSeekBar = new SeekBar(context);
mFrictionSeekBar.setLayoutParams(tableLayoutParams);
seekWrapper.addView(mFrictionSeekBar);

mFrictionLabel = new TextView(getContext());
mFrictionLabel.setTextColor(mTextColor);
params = createLayoutParams(dpToPx(50, resources), ViewGroup.LayoutParams.MATCH_PARENT);
mFrictionLabel.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
mFrictionLabel.setLayoutParams(params);
mFrictionLabel.setMaxLines(1);
seekWrapper.addView(mFrictionLabel);

View nub = new View(context);
params = createLayoutParams(dpToPx(60, resources), dpToPx(40, resources));
params.gravity = Gravity.TOP | Gravity.CENTER;
nub.setLayoutParams(params);
nub.setOnTouchListener(new OnNubTouchListener());
nub.setBackgroundColor(Color.argb(255, 0, 164, 209));
root.addView(nub);

return root;
}

/**
* remove the configurator from its parent and clean up springs and listeners
*/
Expand All @@ -136,14 +228,14 @@ public void destroy() {
public void refreshSpringConfigurations() {
Map<SpringConfig, String> springConfigMap = springConfigRegistry.getAllSpringConfig();

springArrayAdapter.clear();
spinnerAdapter.clear();
mSpringConfigs.clear();

for (Map.Entry<SpringConfig, String> entry : springConfigMap.entrySet()) {
mSpringConfigs.add(entry.getKey());
springArrayAdapter.add(entry.getValue());
spinnerAdapter.add(entry.getValue());
}
springArrayAdapter.notifyDataSetChanged();
spinnerAdapter.notifyDataSetChanged();
if (mSpringConfigs.size() > 0) {
mSpringSelectorSpinner.setSelection(0);
}
Expand Down Expand Up @@ -256,5 +348,63 @@ public void onSpringActivate(Spring spring) {
public void onSpringEndStateChange(Spring spring) {
}
}

private class SpinnerAdapter extends BaseAdapter {

private final Context mContext;
private final List<String> mStrings;

public SpinnerAdapter(Context context) {
mContext = context;
mStrings = new ArrayList<String>();
}

@Override
public int getCount() {
return mStrings.size();
}

@Override
public Object getItem(int position) {
return mStrings.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

public void add(String string) {
mStrings.add(string);
notifyDataSetChanged();
}

/**
* Remove all elements from the list.
*/
public void clear() {
mStrings.clear();
notifyDataSetChanged();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView;
if (convertView == null) {
textView = new TextView(mContext);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
textView.setLayoutParams(params);
int twelvePx = dpToPx(12, getResources());
textView.setPadding(twelvePx, twelvePx, twelvePx, twelvePx);
textView.setTextColor(mTextColor);
} else {
textView = (TextView) convertView;
}
textView.setText(mStrings.get(position));
return textView;
}
}
}

49 changes: 49 additions & 0 deletions rebound-android/src/main/java/com/facebook/rebound/ui/Util.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.facebook.rebound.ui;

import android.content.res.Resources;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;

/**
* Utilities for generating view hierarchies without using resources.
*/
public abstract class Util {

public static final int dpToPx(float dp, Resources res) {
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
res.getDisplayMetrics());
}

public static final FrameLayout.LayoutParams createLayoutParams(int width, int height) {
return new FrameLayout.LayoutParams(width, height);
}

public static final FrameLayout.LayoutParams createMatchParams() {
return createLayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
}

public static final FrameLayout.LayoutParams createWrapParams() {
return createLayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}

public static final FrameLayout.LayoutParams createWrapMatchParams() {
return createLayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT);
}

public static final FrameLayout.LayoutParams createMatchWrapParams() {
return createLayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}

}
Loading

0 comments on commit 0a5b504

Please sign in to comment.