Android Adding Text inside switch toggle. Newer API approach - android

I want to add text inside switches and expect toggle to completely cover the texts
I was able to achieve this in API 16 with below option
<Switch
android:textOff="off"
android:showText="true"
android:textOn="on"/>
However same switch looks odd in the higher version(i'm testing with API 27) where switch toggle is a round icon behind the text.
Is there a way i can fit the text inside the switch toggle using native library/methods.

I found this code in GitHub. After some addition and modification, I get what I need. This toggle button has YES NO text on it and works like switch button. You can give it a go.
public class ToggleButton extends RelativeLayout implements View.OnClickListener {
FrameLayout layout;
TextView toggleCircle;
View background_oval_off, background_oval_on;
int dimen;
private Boolean _crossfadeRunning = false;
private ObjectAnimator _oaLeft, _oaRight;
public ToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.toggle_button, this, true);
background_oval_off = findViewById(R.id.background_oval_off);
background_oval_on = findViewById(R.id.background_oval_on);
toggleCircle = findViewById(R.id.toggleCircle);
layout = (FrameLayout) findViewById(R.id.layout);
layout.setOnClickListener(this);
//get a pixel size for a particular dimension - will differ by device according to screen density
dimen = getResources().getDimensionPixelSize(R.dimen.toggle_width);
_oaLeft = ObjectAnimator.ofFloat(toggleCircle, "x", dimen / 2, 0).setDuration(250);
_oaRight = ObjectAnimator.ofFloat(toggleCircle, "x", 0, dimen / 2).setDuration(250);
//setState();
}
public ToggleButton(Context context) {
this(context, null);
}
public void setState(String answer) {
Log.d("simul", "ans - " + answer);
if (answer.equals("1")) {
toggleCircle.setTextColor(ContextCompat.getColor(getContext(), R.color.green));
toggleCircle.setX(dimen / 2);
_crossfadeViews(background_oval_off, background_oval_on, 1);
toggleCircle.setText("Yes");
} else {
toggleCircle.setTextColor(ContextCompat.getColor(getContext(), R.color.red));
toggleCircle.setX(0);
_crossfadeViews(background_oval_on, background_oval_off, 1);
toggleCircle.setText("No");
}
}
private void _crossfadeViews(final View begin, View end, int duration) {
_crossfadeRunning = true;
end.setAlpha(0f);
end.setVisibility(View.VISIBLE);
end.animate().alpha(1f).setDuration(duration).setListener(null);
begin.animate().alpha(0f).setDuration(duration).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
begin.setVisibility(View.GONE);
_crossfadeRunning = false;
}
});
}
#Override
public void onClick(View view) {
if (_oaLeft.isRunning() || _oaRight.isRunning() || _crossfadeRunning) return;
if (toggleCircle.getText().equals("Yes")) {
_oaLeft.start();
_crossfadeViews(background_oval_on, background_oval_off, 110);
toggleCircle.setText("No");
toggleCircle.setTextColor(ContextCompat.getColor(getContext(), R.color.red));
mListener.toggleButtonClickListener("No");
} else {
_oaRight.start();
_crossfadeViews(background_oval_off, background_oval_on, 400);
toggleCircle.setText("Yes");
toggleCircle.setTextColor(ContextCompat.getColor(getContext(), R.color.green));
mListener.toggleButtonClickListener("Yes");
}
}
public ToggleButtonListener mListener = null;
public void setToggleButtonClickListener(ToggleButtonListener listener) {
mListener = listener;
}
public interface ToggleButtonListener {
public void toggleButtonClickListener(String content);
}
}
toogle_button_red_oval.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="#dimen/toggle_circle_diameter">
<shape android:shape="oval">
<solid android:color="#color/red"/>
<size
android:height="#dimen/toggle_circle_diameter"
android:width="#dimen/toggle_circle_diameter" />
</shape>
</item>
<item android:left="#dimen/toggle_circle_radius" android:right="#dimen/toggle_circle_radius">
<shape android:shape="rectangle">
<solid android:color="#color/red"/>
<size
android:height="#dimen/toggle_circle_diameter"
android:width="#dimen/toggle_circle_diameter" />
</shape>
</item>
<item android:left="#dimen/toggle_circle_diameter">
<shape android:shape="oval">
<solid android:color="#color/red"/>
<size
android:height="#dimen/toggle_circle_diameter"
android:width="#dimen/toggle_circle_diameter" />
</shape>
</item>
</layer-list>
toogle_button_green_oval.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="#dimen/toggle_circle_diameter">
<shape android:shape="oval">
<solid android:color="#color/green"/>
<size
android:height="#dimen/toggle_circle_diameter"
android:width="#dimen/toggle_circle_diameter" />
</shape>
</item>
<item android:left="#dimen/toggle_circle_radius" android:right="#dimen/toggle_circle_radius">
<shape android:shape="rectangle">
<solid android:color="#color/green"/>
<size
android:height="#dimen/toggle_circle_diameter"
android:width="#dimen/toggle_circle_diameter" />
</shape>
</item>
<item android:left="#dimen/toggle_circle_diameter">
<shape android:shape="oval">
<solid android:color="#color/green"/>
<size
android:height="#dimen/toggle_circle_diameter"
android:width="#dimen/toggle_circle_diameter" />
</shape>
</item>
</layer-list>
toogle_button_circle.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="#color/white"/>
<size
android:height="#dimen/toggle_circle_diameter"
android:width="#dimen/toggle_circle_diameter" />
</shape>
toogle_button.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:id="#+id/layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:layout_width="#dimen/toggle_width"
android:layout_height="#dimen/toggle_height"
android:id="#+id/background_oval_off"
android:background="#drawable/toggle_button_black_oval" />
<View
android:layout_width="#dimen/toggle_width"
android:layout_height="#dimen/toggle_height"
android:id="#+id/background_oval_on"
android:background="#drawable/toggle_button_green_oval"
android:visibility="gone" />
<TextView
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:layout_width="#dimen/toggle_circle_diameter"
android:layout_height="#dimen/toggle_circle_diameter"
android:layout_gravity="center_vertical"
android:id="#+id/toggleCircle"
android:textSize="#dimen/toggle_text_size"
android:text="No"
android:background="#drawable/toggle_button_circle"/>
</FrameLayout>
</merge>
XML layout code
<package.name.ToggleButton
android:id="#+id/toggleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</cpackage.name.ToggleButton>
Java Code :
ToggleButton toggleButton = findViewById(R.id.toggleButton);
toggleButton.setToggleButtonClickListener(new ToggleButton.ToggleButtonListener() {
#Override
public void toggleButtonClickListener(String content) {
if (content.equals("Yes")) {
} else {
}
}
});
dimens.xml
<dimen name="toggle_width">100dp</dimen>
<dimen name="toggle_height">50dp</dimen>
<dimen name="toggle_circle_diameter">50dp</dimen>
<dimen name="toggle_circle_radius">25dp</dimen>
Sorry for this long long answer. I had to add all the code here. please let me know if anything missing here. :)

Related

Android : I want to create loader with flight image

I want to create loader in android as same as attached gif
Thanks in advance
Without Plane in your Image I prefer to use ProgressBar
but I will Be More Easy to user SeekBar As Progress Bar
so let`s make it in Simplest way
in Layout XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:hardwareAccelerated="false"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<SeekBar
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:background="#32aaef"
android:id="#+id/sbHeight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:max="100"
android:progress="0"
android:progressDrawable="#drawable/seekbar_as_progress"
android:thumb="#drawable/plane"
/>
</LinearLayout>
And where seekbar_as_progress is
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Define the background properties like color etc -->
<item android:id="#android:id/background">
<shape
android:shape="line"
android:useLevel="true">
<stroke
android:width="3dp"
android:color="#c9c9c9"
android:dashGap="20dp"
android:dashWidth="3dp" />
</shape>
</item>
<!-- Define the progress properties like start color, end color etc -->
<item android:id="#android:id/progress">
<clip>
<shape
android:shape="line"
android:useLevel="true">
<stroke
android:width="6dp"
android:color="#ffffff"
android:dashGap="20dp"
android:dashWidth="4dp" />
</shape>
</clip>
</item>
</layer-list>
and #drawable/plane is plane Icon
And In Your Activity
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// DountChart view = new DountChart(this);
setContentView(R.layout.empty);
final SeekBar sbHeight = findViewById(R.id.sbHeight);
sbHeight.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
sbHeight.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
final int[] progress = {0};
final Handler ha=new Handler();
ha.postDelayed(new Runnable() {
#Override
public void run() {
//call function
if (progress[0] != 100){
AppLogger.log("Prog",progress[0]+"");
progress[0]= progress[0]+1;
sbHeight.setProgress(progress[0]);
ha.postDelayed(this, 100);
}
}
}, 100);
}
and that`s All

SeekBar secondaryProgress not showing

I have a question, I have a seek bar and I want to show the buffer progress of an ExoPlayer media file using the secondary progress bar of the seekBar, the problem is that it´s not showing. Im running on API 21
Here´s the xml code:
<SeekBar
android:id="#+id/seekBarAudioA"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:maxHeight="3dip"
android:minHeight="3dip"
android:progressDrawable="#drawable/seek_bar_progress"
android:secondaryProgressTint="#android:color/holo_blue_dark"
android:thumbTint="#color/amber"
app:layout_constraintBottom_toBottomOf="#+id/play_pause"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toRightOf="#+id/play_pause"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="#+id/play_pause" />
and here´s the java code:
SeekBar = new Thread(new Runnable() {
#Override
public void run() {
try {
while (currentlyPlaying && currentAudioHolder.getAdapterPosition() == audioPosition) {
int duration = (int) exoPlayer.getDuration();
currentAudioHolder.seekBarAudio.setMax(duration);
currentAudioHolder.seekBarAudio.setSecondaryProgress((int) exoPlayer.getBufferedPosition());
final int currPosition = (int) exoPlayer.getCurrentPosition();
Log.d("Buffer", "secondary progress bar position is: " + (int) exoPlayer.getBufferedPosition() + ", and the current position is: " + currPosition);
currentAudioHolder.seekBarAudio.setProgress(currPosition);
((ChatActivity) context).runOnUiThread(new Runnable() {
#Override
public void run() {
currentAudioHolder.audioLength.setText(convertTime(currPosition));
}
});
Thread.sleep(sleep);
}
} catch (InterruptedException i) {
currentlyPlaying = false;
}
}
});
SeekBar.start();
Please help :(
I might be late, but here is my answer: you should check your seek_bar_progress file, that you use for android:progressDrawable, and see if it looks like this:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#android:id/background">
<shape android:shape="rectangle">
<corners android:radius="2dp"/>
<solid android:color="#color/myBgColor"/>
</shape>
</item>
<item android:id="#android:id/secondaryProgress">
<scale android:scaleWidth="100%">
<shape android:shape="rectangle">
<corners android:radius="2dp"/>
<solid android:color="#color/myColor"/>
</shape>
</scale>
</item> <item android:id="#android:id/progress">
<clip>
<shape android:shape="rectangle">
<corners android:radius="2dp"/>
<solid android:color="#color/myColor"/>
</shape>
</clip>
</item>
</layer-list>
I found out that the part with the #android:id/secondaryProgress id was missing in my drawable, and that was the reason why it was not working for me.
Hope it helps.

RecyclerView and out of memory

I'm using RecyclerView to display a few resource-consuming images. My implementation looks like the following:
private class NoteConfigItemAdapter extends RecyclerView.Adapter<NoteConfigItemAdapter.NoteConfigViewHolder> {
public class NoteConfigViewHolder extends RecyclerView.ViewHolder {
private final ToggleButton tbButton;
private final TextView tvDescription;
private int index;
private final View.OnClickListener buttonClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
int oldSelectedItem = selectedItem;
selectedItem = index;
notifyItemChanged(oldSelectedItem);
notifyItemChanged(selectedItem);
}
};
public NoteConfigViewHolder(View itemView) {
super(itemView);
tbButton = (ToggleButton)itemView.findViewById(R.id.notesConfig_tbButton);
tvDescription = (TextView)itemView.findViewById(R.id.notesConfig_tvDescription);
tbButton.setOnClickListener(this.buttonClickListener);
}
public void setData(int descriptionResource, int drawableResource, int index) {
this.index = index;
tvDescription.setText(descriptionResource);
Drawable background = ResourcesCompat.getDrawable(getResources(), drawableResource, null);
tbButton.setBackground(background);
tbButton.setChecked(index == selectedItem);
}
}
private List<NoteConfigItem> configItems;
private int layoutResource;
private int selectedItem = 0;
public NoteConfigItemAdapter(List<NoteConfigItem> configItems, int layoutResource) {
this.configItems = configItems;
this.layoutResource = layoutResource;
}
#Override
public NoteConfigViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater
.from(parent.getContext())
.inflate(layoutResource, parent, false);
return new NoteConfigViewHolder(itemView);
}
#Override
public void onBindViewHolder(NoteConfigViewHolder holder, int position) {
NoteConfigItem item = configItems.get(position);
holder.setData(item.stringResource, item.drawableResource, position);
}
#Override
public int getItemCount() {
return configItems.size();
}
}
Single item's layout contains only ToggleButton and TextView:
I'm dynamically assigning background to the ToggleButton upon binding. Background is a Drawable, which defines two states for the button:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="#color/colorPrimary" />
</shape>
</item>
<item>
<inset android:insetTop="#dimen/selectionBorderSize"
android:insetLeft="#dimen/selectionBorderSize"
android:insetRight="#dimen/selectionBorderSize"
android:insetBottom="#dimen/selectionBorderSize">
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="#ffffff"></solid>
</shape>
</item>
<item>
<bitmap android:src="#drawable/full_range" >
<padding android:bottom="#dimen/selectionBorderSize"
android:top="#dimen/selectionBorderSize"
android:left="#dimen/selectionBorderSize"
android:right="#dimen/selectionBorderSize" />
</bitmap>
</item>
</layer-list>
</inset>
</item>
</layer-list>
</item>
<item android:state_checked="false">
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="#ffffff" />
</shape>
</item>
<item>
<inset android:insetTop="#dimen/selectionBorderSize"
android:insetLeft="#dimen/selectionBorderSize"
android:insetRight="#dimen/selectionBorderSize"
android:insetBottom="#dimen/selectionBorderSize">
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="#ffffff"></solid>
</shape>
</item>
<item>
<bitmap android:src="#drawable/full_range" >
<padding android:bottom="#dimen/selectionBorderSize"
android:top="#dimen/selectionBorderSize"
android:left="#dimen/selectionBorderSize"
android:right="#dimen/selectionBorderSize" />
</bitmap>
</item>
</layer-list>
</inset>
</item>
</layer-list>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#ffffff" />
</shape>
</item>
</selector>
#drawable/fullRange is a PNG image. Itself it is not so big (~hundred of such images occupy around 400kb), but it is quite big (225px x 450px), so I guess the bitmap object created from this PNG can be memory-costly.
When I run the application, I monitor the memory usage. When I only scroll through RecyclerViews, the chart looks like the following:
But when I start to select items, occupied memory starts to grow until OutOfMemoryException:
What am I doing wrong? Why arent the resources being reused/disposed?

Android XML shape drawable is bogging down my UI

I'm using XML drawables and overlaying them ontop of eachother dynamically using layers. Everytime the user hits a button it overlays another image. The issue is that once I have five or ten layers of this particular XML drawable then the UI wants to just lock up. Here is the drawable:
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<rotate
android:fromDegrees="247.5"
android:toDegrees="247.5"
android:pivotX="50%"
android:pivotY="50%">
<shape android:shape="oval">
<size
android:width="800dp"
android:height="800dp"/>
<stroke
android:dashWidth="235.6dp"
android:dashGap="5000.01dp"
android:width="200dp"
android:color="#c2272d" />
</shape>
</rotate>
</item>
<item android:top="0dp" android:bottom="0dp" android:left="0dp" android:right="0dp">
<rotate
android:fromDegrees="247.5"
android:toDegrees="247.5"
android:pivotX="50%"
android:pivotY="50%">
<shape android:shape="oval">
<size
android:width="800dp"
android:height="800dp"/>
<stroke
android:dashWidth="290.6dp"
android:dashGap="5000.01dp"
android:width="60dp"
android:color="#767171" />
</shape>
</rotate>
</item>
</layer-list>
And here is the code I am using to display and update:
public class ShotMagFragment extends Fragment implements DataDelegate, View.OnClickListener{
private ImageView mainImage;
private ArrayList<Drawable> layers = new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_shot_mag, container, false);
View simulateBtn = view.findViewById(R.id.simulateBtn);
simulateBtn.setOnClickListener(this);
mainImage = (ImageView)view.findViewById(R.id.mainImage);
return view;
}
public void displayNewImage() {
Random r = new Random();
int number = 1 + (20 - 20) * r.nextInt();
Drawable d = getResources().getDrawable(getResources().getIdentifier("mag_shade" + number, "drawable", getContext().getPackageName()));
layers.add(d);
final LayerDrawable layerDrawable = new LayerDrawable(layers.toArray(new Drawable[layers.size()]));
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mainImage.setImageDrawable(layerDrawable);
}
});
}
#Override
public void onClick(View v) {
displayNewImage();
}
}
But when I use a different XML drawable I don't get the same UI lock up problem:
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:top="130dp" android:bottom="130dp" android:left="130dp" android:right="130dp">
<rotate
android:fromDegrees="247.5"
android:toDegrees="247.5"
android:pivotX="50%"
android:pivotY="50%">
<shape android:shape="oval">
<size
android:width="540dp"
android:height="540dp"/>
<stroke
android:dashWidth="212.0dp"
android:dashGap="5000.01dp"
android:width="4dp"
android:color="#fff" />
</shape>
</rotate>
</item>
</layer-list>
EDIT
I also get a weird error icon next to my reference to my drawable. When I click on it, it just takes me to the drawable. I have no idea if that is related to my problem, if it is a real error, or if it is just a notice.

ImageButton background change with custom drawable state

I have a custom ImageButton class mimicing the ToggleButton's checked state based on this tutorial How to add a custom button state .
Everything works fine, when I have a state list drawable as the android:src attribute, but the custom state doesn't work with the ImageButton's android:background attribute.
Here is my code:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.ImageButton;
public class CheckableImageButton extends ImageButton implements Checkable {
private static final int[] STATE_CHECKED = {R.attr.state_checked};
private boolean mChecked = false;
public CheckableImageButton(Context context) {
super(context);
}
public CheckableImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if(mChecked){
mergeDrawableStates(drawableState, STATE_CHECKED);
}
return drawableState;
}
#Override
public boolean isChecked() {
return mChecked;
}
#Override
public void setChecked(boolean checked) {
mChecked = checked;
refreshDrawableState();
}
#Override
public void toggle() {
setChecked(!mChecked);
}
}
And the relevant snippet from the layout XML:
<com.my.package.view.CheckableImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#drawable/header_button_bg"
android:padding="5dp"
android:src="#drawable/menu_button"
tools:ignore="ContentDescription" />
And the state list drawable:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/my.package" >
<item android:state_pressed="true">
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#ff000000" />
<gradient android:angle="-90" android:endColor="#d2914e" android:startColor="#906434" />
<corners android:radius="5dp" />
</shape>
</item>
<item app:state_checked="true">
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#ff000000" />
<gradient android:angle="-90" android:endColor="#d2914e" android:startColor="#906434" />
<corners android:radius="5dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#ff000000" />
<gradient android:angle="-90" android:endColor="#4f5b6c" android:startColor="#345b75" />
<corners android:radius="5dp" />
</shape>
</item>
</selector>
Another wonderful trait of eclipse probably..
When I tried to revert my code to the last working version by hand (the state list drawable in the android:src tag), it produced the same error. I reverted from the SVN repo, it worked. Then I made the exact same changes as before, character by character, no difference, and voilá, it works now!
So that's it, the code in the question is fully functional.

Categories

Resources