How to make double seekbar in android? - android

I am building an android application where the user select the a maximum value by seekbar.
I need another button on the same seekbar so that user can select maximum and minimum value from a particular unique seekbar.
Here is my code of single seek bar -
package com.ui.yogeshblogspot;
public class CustomSeekBarExActivity extends Activity implements OnSeekBarChangeListener{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SeekBar bar=(SeekBar)findViewById(R.id.seekBar1);
bar.setOnSeekBarChangeListener(this);
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
TextView tv=(TextView)findViewById(R.id.textView2);
tv.setText(Integer.toString(progress)+"%");
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
}
Here is my xml code of seek bar -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#FFFFFF">
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Choose Your Progress"
android:textColor="#000000"
android:textAppearance="?android:attr/textAppearanceMedium" />
<SeekBar
android:id="#+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:progressDrawable="#xml/progress"
android:max="100"
android:thumb="#xml/thumb"/>
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:gravity="center"
android:layout_gravity="center"
android:paddingTop="10dp"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

Fully Customize two way and single way seek bar you can provide thumb color etc
http://codingsignals.com/crystal-range-seekbar-in-android/
Add in your gradle
dependencies {
compile 'com.crystal:crystalrangeseekbar:1.0.0'
}
<com.crystal.crystalrangeseekbar.widgets.BubbleThumbRangeSeekbar
android:id="#+id/rangeSeekbar5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:corner_radius="10"
app:min_value="0"
app:max_value="100"
app:steps="5"
app:bar_color="#F7BB88"
app:bar_highlight_color="#E07416"
app:left_thumb_image="#drawable/thumb"
app:right_thumb_image="#drawable/thumb"
app:left_thumb_image_pressed="#drawable/thumb_pressed"
app:right_thumb_image_pressed="#drawable/thumb_pressed"
app:data_type="_integer"/>

The Android widget class library has only one slider control, seekbar with only one thumb control. Did some research online and found this cool custom widget, range-seek-bar.
you can followed any one of below
https://github.com/edmodo/range-bar
https://code.google.com/p/range-seek-bar/
https://github.com/Larpon/RangeSeekBar

From Here
<com.appyvet.rangebar.RangeBar
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="#+id/SearchrangeSeekbarAge"
android:layout_width="match_parent"
android:layout_height="72dp"
custom:tickStart="18"
custom:tickInterval="1"
custom:tickEnd="70" />
<com.appyvet.rangebar.RangeBar
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="#+id/SearchrangeSeekbarHeight"
android:layout_width="match_parent"
android:layout_height="72dp"
custom:tickStart="4.5"
custom:tickInterval="0.10"
custom:tickEnd="7.0" />
rangebar.setOnRangeBarChangeListener(new RangeBar.OnRangeBarChangeListener() {
#Override
public void onRangeChangeListener(RangeBar rangeBar, int leftPinIndex,
int rightPinIndex,
String leftPinValue, String rightPinValue) {
}
});

Now that RangeSlider is officially added to Material Components and supports desired options I suggest using that instead of external libraries.
First of all you should add view to your XML layout:
<com.google.android.material.slider.RangeSlider
android:id="#+id/range_seek_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:valueFrom="0.0"
android:valueTo="100.0"
app:values="#array/initial_slider_values"/>
then add initial slider values to arrays
<resources>
<array name="initial_slider_values">
<item>20.0</item>
<item>70.0</item>
</array>
</resources>
after that you can access RangeSlider values in code:
binding.rangeSeekBar.addOnChangeListener { slider, value, fromUser ->
Logger.d(slider.values)
}
where values is a List of floats with 2 member

You do not need to use two seekbar , but you can just do the same function of minimum and maximum by using only one seekbar with having two thumbs over it
Here its a library you can use https://code.google.com/p/range-seek-bar/
You can use by using below code
private final Thumb getClosestThumb(float touchX)
{
double xValue = screenToNormalized(touchX);
return (Math.abs(xValue - normalizedMinValue) < Math.abs(xValue - normalizedMaxValue)) ? Thumb.MIN : Thumb.MAX;
}
And in the "public boolean onTouchEvent(MotionEvent event)",
if(pressedThumb == null),
pressedThumb = getClosestThumb(mDownMotionX);

RangeSeekBar https://github.com/RanaRanvijaySingh/RangeSeekBar. Also there are other libraries available which offers a lot of customization. If you want to go for more interactive design then look for Material Range Bar http://android-arsenal.com/details/1/1272.

You can use this libraby of mine. It comes with a lots of cutomizations. It supports seeking progress in both directions.

I think this link also might be helpful .range-seek-bar .
There is an explanation about it at jitpack.io.

Related

I want to set a transparent background layer when I click on the floating action menu.

This is what I have done so far. Created FloatingActionButton. Now As the + icon is pressed a translucent layer should be there at the back.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.getbase.floatingactionbutton.FloatingActionsMenu
android:id="#+id/actionMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="60dp"
fab:fab_addButtonColorNormal="#color/primary"
fab:fab_addButtonColorPressed="#color/primary_dark"
fab:fab_addButtonPlusIconColor="#ffffff">
<com.getbase.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="openAudio"
fab:fab_colorNormal="#EA1E63"
fab:fab_colorPressed="#EA1E63"
fab:fab_icon="#drawable/ic_action_mic" />
</com.getbase.floatingactionbutton.FloatingActionsMenu>
</RelativeLayout
Try this.
floatingActionMenuButton.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
#Override
public void onMenuToggle(boolean opened) {
if (opened) {
//menu opened
} else {
//menu closed
}
}
});
use setBackgroundResource or setBackgroundColor. I think first is pretty simple.
Second one takes an int as an argument. So, just convert your hex color (for example #55000000) into decimal and it will work as well.
I had the same issue and i fixed it in following way.
I added a relative layout which will match parent in both width and height.
Set its background color to black and set alpha to your required opacity.
<RelativeLayout
android:id="#+id/obstructor"
android:visibility="invisible"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:alpha="0.75"
android:background="#android:color/black">
</RelativeLayout>
And then on the menu item expanded and collapsed make this visible and invisible.
mFabMenu = (FloatingActionsMenu) findViewById(R.id.multiple_actions);
final RelativeLayout obstrucuterView = (RelativeLayout) findViewById(R.id.obstructor);
obstrucuterView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (obstrucuterView.getVisibility() == View.VISIBLE) {
mFabMenu.collapse();
return true;
}
return false;
}
});
mFabMenu.setOnFloatingActionsMenuUpdateListener(new FloatingActionsMenu.OnFloatingActionsMenuUpdateListener() {
#Override
public void onMenuExpanded() {
if (obstrucuterView.getVisibility() == View.INVISIBLE)
obstrucuterView.setVisibility(View.VISIBLE);
}
#Override
public void onMenuCollapsed() {
if (obstrucuterView.getVisibility() == View.VISIBLE)
obstrucuterView.setVisibility(View.INVISIBLE);
}
});
Hope this helps.
There is another custom library which is more advanced than what you are using right now.
Get it here
Clans floating Action Button
Set this to true and it will solve your problem. Do let me know if it helps
fabPlusButton.setClosedOnTouchOutside(true);
If you are using Clans floating Action Button then perhaps fab:menu_backgroundColor might be something that you could have a look at if it satisfies your use-case. ofcourse the layout width and height should both match parent (This solution has worked for me)

How to attach OnClickListener to a button in a custom preference layout?

I have a preference screen that is populated with items from a database. I have this working by creating my own PreferenceActivity. In the activity I create DialogPreference items and add them to my PreferenceCategory To style to preference item on the screen I use a custom layout and apply it using setLayoutResource(R.layout.custom_pref_row)
This basically adds an ImageButton to the view aligned to the right of the layout. This all works fine and my preference screen shows the custom view with the button. My question is how do I attach a click listener to the button in the custom view? I was not able to find a way to get at View for the row from the PreferenceActivity. If my items were not created dynamically I might be able to do this all from XML and then reference the id or the button, but I can do that because I am creating the list dynamically.
Any suggestions on how to get a handle on the ImageButton for each item? In the end I want to configure the button to launch a delete confirmation dialog.
R.layout.custom_pref_row:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="#+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="#+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#android:id/title"
android:layout_alignLeft="#android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:maxLines="2" />
<ImageButton android:id="#+id/pref_delete_station" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="#drawable/ic_trash_can" android:layout_alignParentRight="true" android:background="#null"></ImageButton>
</RelativeLayout>
<!-- Preference should place its actual preference widget here. -->
<LinearLayout android:id="#+android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="vertical" />
</LinearLayout>
Related part of my PreferenceActivity:
DialogPreference diaPref;
for (Station mStation : sList) {
diaPref = new StationEditor(this.getPreferenceScreen().getContext(), null, this, mStation);
diaPref.setLayoutResource(R.layout.custom_pref_row);
diaPref.setTitle(mStation.getName());
diaPref.setKey(STATION_PREFIX + mStation.getId());
// add new preference
stationTypesCategory.addPreference(diaPref);
}
You can extend DialogPreference and override the onBindDialogView(View view). Inside this method you can do:
#Override
protected void onBindDialogView(View view) {
((ImageButton) view.findViewById(R.id.pref_delete_station)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
super.onBindDialogView(view);
}
Your sublcass of DialogPreference can hold any state/value related to the item it represents.
Take a look at this question about general guidelines to extend DialogPreference.
Hope this helps!
OK, Chopin got me thinking in a different direction. I did not realize that the Preference object is also responsible for how its selector appears in a Preference screen.
The setLayoutResouce() function sets the resource for the Dialog itself not the row seen in a Preference screen. This was confusing and I was incorrectly trying to use this in the preference screen to adjust the selector layout there.
The solution is to override onCreateView and return a custom layout there. To me this is counterintuitive because that method usually controls the final view in most other situations.
I alraedy subclassed my Preference (DialogPreference) so all I had to do was add the following...
#Override
protected View onCreateView (ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View customRow = inflater.inflate(R.layout.preferences_station_list_row, null);
((ImageButton) customRow.findViewById(R.id.pref_delete_station)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i("c","clicked");
}
});
customRow.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
showDialog(null);
}
});
customRow.setClickable(true);
return customRow;
}
One problem I ran into was that at first the row itself was no longer clickable but the button was. I had to add a listener on the whole view and manually call ShowDialog(). The only thing missing now is that when clicked from the Preference screen the item no longer shows a highlight. Any idea what styles I should apply so the list shows the highlight like it normally does?

android: How to make settings navigation like native settings app

How do I make the settings navigation for SwitchReference like Android native settings app?
Where when u click on WiFi region(not on the switch) it will navigate to a new screen:
My app only change the switch from ON to OFF and vice versa even when I'm not clicking on the switch.
I'm using PreferenceFragment and xml for the screen. And my preference is following the example from Android PreferenceFragment documentation. I develop my app on ICS 4.0 API 14.
Anyone know how to do this?
Edited:
My XML look like this:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:layout="#layout/preference_category"
android:title="User Settings" >
<SwitchPreference
android:key="pref_autorun"
android:layout="#layout/preference"
android:summary="Autorun SMODE on boot"
android:title="Autorun SMODE" />
<SwitchPreference
android:key="pref_wifi_control"
android:layout="#layout/preference"
android:selectable="false"
android:summary="Controls your Wi-Fi radio automatically based on hotspot availability"
android:title="Wi-Fi Radio Control" />
</PreferenceCategory>
</PreferenceScreen>
By taking a look at the source of the stock Settings app, you can find how they did it.
Basically, they use a custom ArrayAdapter (much like you would do with a ListView) to display rows with Switch buttons. And for the second screen, they simply use the CustomView available in the ActionBar.
I wrote an article with a sample code to show how you can do it in your project. Be careful though, this can only wirk in API Level 14 or higher, so if you target older devices, keep an old style preference screen.
I see 2 questions here: 1. How to listen to preference click outside the switch area? 2. How to put a switch in the actionbar?
I'll answer question 1:
I created a new SwitchPreference class and overrode the onClick method to do nothing. This prevents the setting change when clicking outside the switch.
public class SwitchPreference extends android.preference.SwitchPreference {
#Override
protected void onClick() {
}
}
Usage (xml):
<android.util.SwitchPreference
android:key="whatever"
android:title="Whatever" />
Usage (java):
SwitchPreference switchPreference = (SwitchPreference) findPreference("whatever");
switchPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
DialogUtils.showToast(Preferences.this, "Clicked outside switch");
return true;
}
});
switchPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
DialogUtils.showToast(Preferences.this, "Clicked inside switch and setting changed");
return true;
}
});
I gave this one a try and struggled a bit. I thought I would share my experience.
At first I tried the answer by XGouchet since it had the most up votes. The solution was fairly complicated and required using preference headers which are very cool but did not fit what I was doing. I decided the easiest thing for me to do is to wrap up my preferenceFragment in a regular fragment and make fake the switch preference with a regular view. I dug up the android source for a preference and came up with this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.lezyne.link.ui.homeScreen.settingsTab.SettingsFragment">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
</FrameLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:background="#e1e1e1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingRight="?android:attr/scrollbarSize">
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="6dip"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_weight="1">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#android:id/title"
android:layout_below="#android:id/title"
android:maxLines="4"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
</RelativeLayout>
<!-- Preference should place its actual preference widget here. -->
<RelativeLayout
android:id="#+id/widget_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingEnd="36dp">
<Switch
android:thumb="#drawable/switch_inner"
android:id="#+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true" />
<TextView
android:id="#+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:text="#string/Notifications"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:background="#e1e1e1" />
</LinearLayout>
The FrameLayout at the top gets a preference fragment like so
getChildFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new SettingsPreferencesFragment(), "SettingsPreferencesFragment")
.commit();
Then I can get assign my click listeners as I would in any regular view. SettingsPreferencesFragment is just totally standard preference fragment.
This solution seemed pretty good, but then I noticed weird layout issues on tablets. I realized that I would have trouble getting this solution to look right on all devices and I needed to use a real switchPreference not a fake one.
============== Solution 2 ===============
AlikElzin-kilaka's solution was nice and simple but did not work when I tried. I tried a 2nd time to make sure that I had not just done it wrong. I kept playing around and came up with something that seems to work. He has a good point about
2 questions here: 1. How to listen to preference click outside the
switch area? 2. How to put a switch in the actionbar?
Really only question (1) is worth answering because question 2 has been answered here and other places
I realized the only way to get access to the views in a preference was to create a child class and override onBind. So I came up with this child class of SwitchPreference that creates separate click handlers for the switch as the entire view. Its still a hack though.
public class MySwitchPreference extends SwitchPreference {
public MySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MySwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
getView(null,null);
}
public MySwitchPreference(Context context) {
super(context);
}
public interface SwitchClickListener{
public void onSwitchClicked(boolean checked);
public void onPreferenceClicked();
}
private SwitchClickListener listener = null;
public void setSwitchClickListener(SwitchClickListener listener){
this.listener = listener;
}
public Switch findSwitchWidget(View view){
if (view instanceof Switch){
return (Switch)view;
}
if (view instanceof ViewGroup){
ViewGroup viewGroup = (ViewGroup)view;
for (int i = 0; i < viewGroup.getChildCount();i++){
View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup){
Switch result = findSwitchWidget(child);
if (result!=null) return result;
}
if (child instanceof Switch){
return (Switch)child;
}
}
}
return null;
}
protected void onBindView (View view){
super.onBindView(view);
final Switch switchView = findSwitchWidget(view);
if (switchView!=null){
switchView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener!=null) listener.onSwitchClicked(switchView.isChecked());
}
});
switchView.setFocusable(true);
switchView.setEnabled(true);
}
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener!=null) listener.onPreferenceClicked();
}
});
}
}
It uses the recursive function findSwitchWidget to walk the tree until it finds a Switch. I would have rather write code like this:
Switch switchView = view.findViewById(android.R.id.switchView);
but there does not seem to be a way to get to that internal id value that I know of. Anyhow once we have the actual switch we can assign listeners to it and the container view. The switch preference won't update automatically so its necessary to save the preference yourself.
MySwitchPreference switchPreference = (MySwitchPreference) findPreference("whatever");
switchPreference.setSwitchClickListener(new MySwitchPreference.SwitchClickListener() {
#Override
public void onSwitchClicked(boolean checked) {
//Save the preference value here
}
#Override
public void onPreferenceClicked() {
//Launch the new preference screen or activity here
}
});
Hopefully this 2nd hack wont come back to bite me.
Any one see any potential pitfalls of this method?
I also put a slightly improved version of the code on github https://gist.github.com/marchold/45e22839eb94aa14dfb5

Coupling Android layout to its logic outside of the owner Activity

I'm facing some complexities when developing a medium-complex Android application. I'm searching for information about the possibility of using code-behind-like techniques for easier maintanability of Android software.
Currently (please highlight anything wrong), I have found that in order to make a multi-step wizard with extra dialogs (eg. dialogs that are not part of the main sequence) I need to code a single XML layout file with a single ViewFlipper containing each subview as child node. Today I discovered how to navigate across views more than forward/backward (viewFlipper.setDisplayedChild(i)), giving access to extra views.
Now all the Java code is contained within the main Activity class, which is beginning to look bad. As an experienced .NET developer I have learned how to use custom controls to wrap both layout and business logic inside modules.
I know that in Android I can define a view programmatically as an independent class and add it to the main layout programmatically, however I want to know if it's possible in Android to define a layout by XML (for easier WYSIWYG creation/editing) and define all the code within a dedicated class, with initialization logic, button callbacks, async tasks, etc.
I'm not sure if it's feasible or there is a good compromise that can be achieved.
I have read this question without clearing my doubts.
Thank you.
Code examples:
An extract of the layout file (I expect 4 wizard steps, a help view and an EULA view)
<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/view_phone"
style="#android:style/Theme.Light.NoTitleBar"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<!-- First screen/welcome -->
<LinearLayout
android:id="#+id/view_phone_screen1"
style="#android:style/Theme.Light.NoTitleBar"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:weightSum="100" >
<TextView
android:id="#+id/view_phone_screen1_lblChooseProvider"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:text="#string/view_phone_lblChooseProvider_1ststep"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ImageButton
android:id="#+id/view_phone_btnFrecciarossa"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:contentDescription="#string/provider_FRECCIAROSSA"
android:gravity="center_vertical|clip_vertical"
android:padding="10dp"
android:src="#drawable/logo_frecciarossa"
android:tag="#+id/provider_FRECCIAROSSA" />
<ImageButton
android:id="#+id/view_phone_btnItalo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:contentDescription="#string/provider_ITALO"
android:gravity="center_vertical|clip_vertical"
android:padding="10dp"
android:src="#drawable/logo_italo"
android:tag="#+id/provider_ITALO" />
</LinearLayout>
<!-- Second screen - will need to do some asynchronous task -->
<RelativeLayout
android:id="#+id/view_phone_screen2"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="#+id/view_phone_screen2_lblConnectingToWifi"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:text="#string/view_phone_lblConnectToWifi_2ndstep"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/view_phone_step2_lblConnectedToWifi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/imageView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="58dp"
android:text="#string/view_phone_step2_connectingToWifi"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/view_phone_step2_lblPhoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/editText1"
android:layout_below="#+id/view_phone_step2_lblConnectedToWifi"
android:layout_marginTop="51dp"
android:text="#string/view_phone_step2_msgInputPhoneNumber"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/view_phone_step2_lblUnableDetectPhoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="#string/view_phone_step2_msgUnableDetectPhoneNumber"
android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="invisible" />
<Button
android:id="#+id/view_phone_screen2_backward"
style="#style/buttonBackward" />
<Button
android:id="#+id/view_phone_screen2_forward"
style="#style/buttonForward_disabled"
android:enabled="false" />
<EditText
android:id="#+id/view_phone_step2_txtPhoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="#+id/view_phone_step2_lblPhoneNumber"
android:layout_below="#+id/view_phone_step2_lblPhoneNumber"
android:inputType="phone"
android:singleLine="true" >
<requestFocus />
</EditText>
</RelativeLayout>
</ViewFlipper>
Code example from Activity (expect to implement ALL the logic of 4+2 step wizard)
public class MyActivity extends Activity {
/** Called when the activity is first created. */
private final static String LOG_TAG = "LOG_TAG";
private int stepNumber;
#Override
public void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
super.onCreate(savedInstanceState);
this.stepNumber=1;
setContentView(R.layout.view_phone);
//This class wraps the click for the two buttons
ProviderSelectionListener providerSelectionListener = new ProviderSelectionListener(this);
this.findViewById(R.id.view_phone_btnFrecciarossa).setOnClickListener(providerSelectionListener);
this.findViewById(R.id.view_phone_btnItalo).setOnClickListener(providerSelectionListener);
}
#Override
protected void onPause() {
super.onPause();
try {
if (MyApplication.getPlatformManager() != null)
MyApplication.getPlatformManager().onApplicationPause();
} catch (MyCustomException e) {
// WTF (Worse Than Failure!)
Log.e(LOG_TAG, super.getString(R.string.zf_error_unknown_error_pauseactivity), e);
e.printStackTrace();
}
}
#Override
protected void onResume() {
super.onResume();
try {
if (MyApplication.getPlatformManager() != null)
MyApplication.getPlatformManager().onApplicationResume();
} catch (MyCustomException e) {
// WTF (Worse Than Failure!)
Log.e(LOG_TAG, super.getString(R.string.zf_error_unknown_error_pauseactivity), e);
e.printStackTrace();
}
}
/*
* SLIDE INIZIO
*/
protected void slideNext() {
ViewFlipper vf = (ViewFlipper) findViewById(R.id.view_phone);
vf.setOutAnimation(getApplicationContext(), R.anim.slide_out_left);
vf.setInAnimation(getApplicationContext(), R.anim.slide_in_right);
vf.showNext();
}
protected void slidePrevious() {
ViewFlipper vf = (ViewFlipper) findViewById(R.id.view_phone);
vf.setOutAnimation(getApplicationContext(), R.anim.slide_out_right);
vf.setInAnimation(getApplicationContext(), R.anim.slide_in_left);
vf.showPrevious();
}
/*
* SLIDE FINE
*/
/*
* STEP 1 INIZIO
*/
public void completeStep1(ISmsWifiProvider provider) {
if (provider == null) {
Log.e(LOG_TAG, "Provider nullo");
return;
}
MyApplication.setAuthenticationProvider(provider);
slideNext();
initializeStep2();
}
public void returnToStep1() {
MyApplication.setAuthenticationProvider(null);
slidePrevious();
}
/*
* STEP 1 FINE
*/
/*
* STEP 2 INIZIO
*/
private void initializeStep2() {
// Event handler
Button backButton = (Button) findViewById(R.id.view_phone_screen2_backward), fwButton = (Button) findViewById(R.id.view_phone_screen2_forward);
fwButton.setEnabled(false);
backButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
returnToStep1();
}
});
}
/*
* STEP 2 FINE
*/
#Override
public void onBackPressed() {
// This will be called either automatically for you on 2.0
// or later, or by the code above on earlier versions of the
// platform.
return;
}
}
I want to know if it's possible in Android to define a layout by XML (for easier WYSIWYG creation/editing) and define all the code within a dedicated class, with initialization logic, button callbacks, async tasks, etc.
Yes. It is one of the techniques for creating a custom View. For example, I have a custom ColorMixer widget in this project, which can be used directly in an activity, or in a dialog, or in a custom preference.
I agree with your tactical decision to implement a wizard via a ViewFlipper -- see this answer to another StackOverflow question for "Murphy's Theory of the Activity".
I suspect that the right answer, longer term, is for somebody (who might be me) to come up with a Fragment-based wizard pattern, as that gives you the decoupling you desire.

Discrete seekbar in Android app?

I would like to create a seekbar for an Android app that allows the user to select a value between -5 and 5 (which maps to "strongly disagree" and "strongly agree"). How do I make a seekbar with discrete values? or is there a better UI widget I could use for this?
Thanks.
The Seekbar works great for discrete values. We use a Seekbar for discrete data as shown below. To show which item is selected, we just change the font of the selected text view so it is bigger. You could also highlight by changing the background color or something. It works pretty well. You will want to call setMax(11) on the seek bar, and then in your code you need to translate between the range (0 through 11) and (-5 through 5) appropriately.
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<TextView android:text="-5"
android:id="#+id/answerNegative5"
android:textSize="25sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView android:text="-4"
android:id="#+id/answerNegative4"
android:textSize="25sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView android:text="-3"
android:id="#+id/answerNegative3"
android:textSize="25sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
.....
</LinearLayout>
<SeekBar android:id="#+id/intensitySlider"
android:layout_weight="0"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
If you want to implement discrete seekbar with number of gaps without using third party library then use style property of seekbar.
<SeekBar
android:id="#+id/sb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="10"
android:thumb="#drawable/ic_location"
android:theme="#style/Widget.AppCompat.SeekBar.Discrete" />
I don't know what is the issue here, you add a seekbar having a range of 0-10. Then you can map these values to -5 if you substract -5 from the selected value.
EDIT
add android:max="10" to the xml definiton and you get a fixed size seekbar.
You maybe should consider to add a textview to denote the current selected value's textual representation such as: Strongly Disagree.
To update this view, subscribe to onProgressChanged event and progress parameter will give you the chosen number.
SeekBar s = (SeekBar) findViewById(R.id.SeekBar);
s.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar,
int progress, boolean fromUser) {
}
}
Just use the material components library with something like:
<com.google.android.material.slider.Slider
android:stepSize="1"
android:valueFrom="-5"
android:valueTo="5"
/>
I hope this code surely helpes you.
Try this...
float discrete = 0;
float start = 0;
float end = 100;
float start_pos = 0;
int start_position = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = -10; //you need to give starting value of SeekBar
end = 10; //you need to give end value of SeekBar
start_pos = 5; //you need to give starting position value of SeekBar
start_position = (int)(((start_pos - start) / (end - start)) * 100);
discrete = start_pos;
SeekBar seek = (SeekBar) findViewById(R.id.seekBar1);
seek.setProgress(start_position);
seek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
Toast.makeText(getBaseContext(), "discrete = " + String.valueOf(discrete), Toast.LENGTH_SHORT).show();
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// TODO Auto-generated method stub
// To convert it as discrete value
float temp = progress;
float dis = end - start;
discrete = (start + ((temp / 100) * dis));
}
});
}
1-st step : set maxVal to 10;
2-nd step :
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser)
{
switch(seekBar.getId())
{
case R.id.mySeekBar:
int prValue = progress - 5;
editText.setText(String.valueOf(preValue));
break;
}
}
<SeekBar
android:id="#+id/seekbar"
style="#style/SeekBarWithoutSteps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="22dp"
android:layout_marginRight="22dp"
android:layout_marginTop="#dimen/margin_10"
android:max="4"
android:maxHeight="#dimen/margin_5"
android:minHeight="#dimen/margin_5"
android:paddingLeft="#dimen/margin_10"
android:paddingRight="#dimen/margin_10"
android:progressBackgroundTint="#color/colorGray"
android:progressTint="#color/colorGreen"
android:theme="#style/Widget.AppCompat.SeekBar.Discrete"
android:thumb="#drawable/filled_green"
android:thumbOffset="15dp" />

Categories

Resources