Android Anko seekbar skinning - android

I have a SeekBar in my anko dsl (i use 0.10.4) layout like this
seekBar {
max = 2
progress = 1
progressDrawable = drawable(R.drawable.seek_bar_progress)
thumb = drawable(R.drawable.seek_bar_thumb)
onSeekBarChangeListener {
onProgressChanged { _, progress, _ ->
// Something
}
}
}.lparams(matchParent) {
setMargins(dip(16), dip(8), dip(16), dip(8))
}
seek_bar_progress.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#D9D9D9"/>
</shape>
</item>
<item android:id="#android:id/progress">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/colorRed"/>
</shape>
</item>
seek_bar_thumb.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item >
<shape android:shape="oval">
<solid android:color="#color/colorRed"/>
<size android:height="26dp" android:width="26dp"/>
</shape>
</item>
and i have ugly view with this settings on any android devices
see picture.
But when i use "include" tag i have a correct seekbar implementation see picture
include<SeekBar>(R.layout.seek_lay) {
progress = 1
onSeekBarChangeListener {
onProgressChanged { _, progress, _ ->
// Something
}
}
}.lparams(matchParent) {
setMargins(dip(16), dip(8), dip(16), dip(8))
}
seek_lay.xml
<SeekBar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:max="2"
android:maxHeight="2dp"
android:minHeight="2dp"
android:progress="1"
android:progressDrawable="#drawable/seek_bar_progress"
android:thumb="#drawable/seek_bar_thumb"
/>
does anybody faces with the same problem? And how i can resolve this if it's possible?
Thanks

I face the same problem today.. And I search for hours to solve this problem too, but I could not find any 'normally' solution at all.
Finally I change the field mMaxHeight with java reflection to achieve the result.
Just notice that mMaxHeight belong to ProgressBar.class, so you need to use ProgressBar.class to find it.
val field = ProgressBar::class.java.getDeclaredField("mMaxHeight")
val accessible = field.isAccessible
field.isAccessible = true
field.setInt(seekBar, [value])
field.isAccessible = accessible
Result
I dont know it is a good or bad way, it just can work for me.

Related

Custom AppCompatButton getting wrong colors on Android 5 (Api 21)

So I've implemented a custom button for our app, the implementation works perfect on Android 6 and up but I run into an issue on Android 5, where the background color doesn't get applied until I press the button once. Then it looks as it should.
Buttons not correct
Buttons correct
The implementation looks like this:
class MpButton #JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.style.ButtonStyle) : AppCompatButton(context, attrs, defStyleAttr) {
private val toScale = 0.9f
private val fromScale = 1f
init {
var style = 0
var allCaps = false
attrs?.let {
val a = context.obtainStyledAttributes(it, R.styleable.MpButton)
style = a.getInt(R.styleable.MpButton_MpButtonColor, 0)
allCaps = a.getBoolean(R.styleable.MpButton_MpButtonAllcaps, false)
a.recycle()
}
when (style) {
WHITE -> {
this.setBackgroundResource(R.drawable.mp_button_white)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
RED -> {
this.setBackgroundResource(R.drawable.mp_button_red)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
BLACK -> {
this.setBackgroundResource(R.drawable.mp_button_black)
this.setTextColor(ContextCompat.getColor(context, R.color.mp_black))
}
BLUE -> {
this.setBackgroundResource(R.drawable.mp_button_blue)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
YELLOW -> {
this.setBackgroundResource(R.drawable.mp_button_yellow)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
else -> {
this.setBackgroundResource(R.drawable.mp_button_green)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
}
this.gravity = Gravity.CENTER
val padding = Utils.convertDpToPixel(context, 5)
this.setPadding(padding, padding, padding, padding)
this.isAllCaps = allCaps
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
when(event.action) {
MotionEvent.ACTION_DOWN -> {
this.animate().scaleX(toScale).scaleY(toScale).setDuration(100).start()
}
MotionEvent.ACTION_UP -> {
this.animate().scaleX(fromScale).scaleY(fromScale).setDuration(100).start()
}
}
return super.dispatchTouchEvent(event)
}
companion object {
const val WHITE = 1
const val RED = 2
const val BLACK = 3
const val BLUE = 4
const val YELLOW = 5
}
}
For info Ill also add the XML for one of the colors:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/mp_black">
<item>
<selector
android:exitFadeDuration="#android:integer/config_mediumAnimTime"
android:enterFadeDuration="#android:integer/config_shortAnimTime">
<item android:state_enabled="true" android:state_pressed="false">
<shape android:shape="rectangle">
<corners android:radius="30dp"/>
<solid android:color="#color/jungle_green" />
</shape>
</item>
<item android:state_enabled="true" android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="30dp"/>
<solid android:color="#color/forest" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="rectangle">
<corners android:radius="30dp"/>
<solid android:color="#color/mp_gray_5" />
</shape>
</item>
</selector>
</item>
</ripple>
As a last ill copy the part of the XML of the view aswell to give as much info as possible:
<se.motesplatsen.app.ui.controls.MpButton
android:id="#+id/btnStartLogin"
android:layout_width="220dp"
android:layout_height="44dp"
android:text="#string/DEFAULT_LOGIN"
android:layout_marginBottom="10dp"
android:layout_marginTop="20dp"
app:MpButtonAllcaps="true"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/btnStartBecomeMember"/>
<se.motesplatsen.app.ui.controls.MpButton
android:id="#+id/btnStartBecomeMember"
android:layout_width="220dp"
android:layout_height="44dp"
android:layout_marginTop="25dp"
android:text="#string/BECOME_MEMBER_BUTTON"
app:MpButtonColor="1"
app:MpButtonAllcaps="true"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toBottomOf="#id/tvStartDesc"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="#id/btnStartLogin"/>
UPDATE & SOLUTION!:
Finally got this to work! Solution was to remove
android:exitFadeDuration="#android:integer/config_mediumAnimTime"
android:enterFadeDuration="#android:integer/config_shortAnimTime"
Im guessing it somehow interferes with the ripple animation on certain Android versions. So for anyone else that have my issue, check so you dont have Ripple togheter with fadeduration in the selector :)!
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape >
<solid android:color="#android:color/white"/>
<size android:height="1dp"/>
</shape>
</item>
<item android:bottom="2dip" android:top="2dip" android:left="2dip" android:right="2dip">
<shape>
<solid android:color="#android:color/Transparent"/>
</shape>
</item>
this is exactly look like your correct button
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<corners
android:radius="5dp"
/>
<solid
android:color="#color/Transparent"
/>
just use this as background you are using on pressed state in your file

In Anko, how can I give my button a coloured border?

I took a look at the code but couldn't see how I can add a border to a button. Example button that needs a border:
val memoryButton = button {
backgroundColor = mainColour
textColor = textColour
text = "I am a button!"
onClick {
doSomething()
}
}
Any ideas?
Try this
create file button_border.xml in drawable folder like this
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient android:startColor="#FFFFFF"
android:endColor="#00FF00"
android:angle="270" />
<corners android:radius="3dp" />
<stroke android:width="5px" android:color="#000000" />
</shape>
and simply add this to background of button like this
button {
text = "I am a button!"
background=getDrawable(R.drawable.button_border)
onClick {
println("Hello")
}
}
You will get border to your button :)

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.

Change color of progress bar background in android

I have a Progressbar, which look is defined in a xml file:
<?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>
<corners android:radius="#dimen/round_corners_elements" />
<solid android:color="#color/blue_50" />
<stroke android:width="1px" android:color="#color/light_gray" />
</shape>
</item>
<item android:id="#android:id/progress">
<clip android:clipOrientation="horizontal" android:gravity="left">
<shape>
<corners
android:radius="#dimen/round_corners_elements"
/>
<solid android:color="#color/signaling_color" />
<stroke android:width="1px" android:color="#color/light_gray" />
</shape>
</clip>
</item>
</layer-list>
But as i need to change the background color (blue50) to any other color dynamically, i failed. Anyone got an idea how i can change it programmatically? The progress can stay as it is. The special thing about is, that progress bar has round corners, which is necessary. I tried several approaches, but none worked for me.
setBackgroundTintList didn't worked as is only available >API21
int[][] states = new int[][] { new int[] { android.R.attr.background }, new int[] { -android.R.attr.process } };
int[] colors = new int[] { Color.parseColor("#000000"), Color.BLACK };
ColorStateList myList = new ColorStateList(states, colors);
progressBar.setBackgroundTintList(myList);
progressBar.setBackgroundTintMode(PorterDuff.Mode.SRC_OVER);
setBackgroundColor Also had no effect:
progressBar.setBackgroundColor(ContextCompat.getColor(this, R.color.white));
Anyone got an idea?
You will have to obtain the LayerDrawable used by the ProgressBar and then either
use findDrawableByLayerId(android.R.id.background) to get the Drawable for that layer and make modifications to it at runtime; or
create a new Drawable and call setDrawableByLayerId(android.R.id.background, newBackgroundDrawable)
If I recall correctly, <shape> tags result in a GradientDrawable being created at runtime by the system, and that conveniently has methods like setColor()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
progressBar.setProgressBackgroundTintList(ColorStateList.valueOf(tint));
} else {
LayerDrawable drawable = (LayerDrawable) progressBar.getProgressDrawable();
Drawable background = new ColorDrawable(tint);
drawable.setDrawableByLayerId(android.R.id.background, background);
progressBar.setProgressDrawable(drawable);
}

Scrollbar touch area in Android 6

I observe new behaviour in Android 6.0 Marshmallow. The touching area of scrollbar is widther than the scrollbar. It is visible on following screenshot. Scrollbar has 20 dp (green area) and touching area is probably 48 dp (blue and green area). I would like to have the touch area above the scrollbar only:
I use following:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="MyTheme.Dark" parent="android:Theme.Black">
<item name="android:fastScrollStyle">#style/Widget.FastScroll</item>
<item name="android:scrollbarThumbVertical">#drawable/dark_scrollbar_thumb</item>
<item name="android:scrollbarTrackVertical">#drawable/dark_scrollbar_track</item>
<item name="android:scrollbarSize">4dp</item>
<item name="android:fastScrollThumbDrawable">#drawable/dark_scrollbar_fast_thumb</item>
<item name="android:fastScrollTrackDrawable">#drawable/dark_scrollbar_fast_track</item>
</style>
<style name="Widget.FastScroll" parent="android:Widget.Material.FastScroll">
</style>
</resources>
dark_scrollbar_fast_thumb.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape>
<size
android:height="30dp"
android:width="20dp" />
<solid android:color="#android:color/transparent" />
</shape>
</item>
<item android:left="8dp" android:right="8dp">
<shape>
<size
android:height="30dp"
android:width="4dp" />
<solid android:color="#color/dark_secondary" />
</shape>
</item>
</layer-list>
dark_scrollbar_fast_track.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<size android:width="#dimen/1dp" />
<solid android:color="#color/dark_scrollbar_track" />
</shape>
dark_scrollbar_fast_thumb.xml:
<item>
<shape>
<size
android:height="30dp"
android:width="20dp" />
<solid android:color="#android:color/transparent" />
</shape>
</item>
<item android:left="8dp" android:right="8dp">
<shape>
<size
android:height="30dp"
android:width="4dp" />
<solid android:color="#color/dark_secondary" />
</shape>
</item>
dark_scrollbar_fast_track.xml:
<size android:width="#dimen/1dp" />
<solid android:color="#color/dark_scrollbar_track" />
Fast scrollbar is always visible and I use following style in listviews:
<item name="android:scrollbarStyle">outsideInset</item>
But the result looks more like outsideOverlay. I can observe this issue only on Marshmallow devices.
I would like to find the attribute that causes it and change it from 48dp to 20dp. Would you please help me?
I encountered the same issue and ended up using a workaround.
The trick is to disable the fast scroll when the user is not scrolling (or 1 sec after he stopped scrolling), and reactivate it when he starts scrolling again.
In order to do so, youn need to implement OnScrollListener like this and set the listener to the listview:
private int mCurrentState = 0;
#Override
public void onScrollStateChanged(AbsListView absListView, int state) {
if (state == SCROLL_STATE_IDLE && mCurrentState != state && mListview.isFastScrollEnabled()){
mListview.postDelayed(new Runnable() {
#Override
public void run() {
mListview.setFastScrollEnabled(false);
}
},1000);
}
mCurrentState = state;
}
#Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
if (mCurrentState == SCROLL_STATE_TOUCH_SCROLL) {
if (!mListview.isFastScrollEnabled())
mListview.setFastScrollEnabled(true);
}
}
Hope this might help you
Found a simple solution which honestly I don't understand completely ;)
I created a view overlay for the blue section which should be touch insensitive for the fastscrollbar (parent view is a RelativeLayout).
<View
android:id="#+id/scroll_overlay
android:layout_width="25dp"
android:layout_marginRight="25dp"
android:alignParentTop="true"
android:alignParentRight="true"
android:layout_above="#id/my_list_view_bottom_bar"
android:clickable="true"/>
Then in my list view fragment, I set up an OnTouchListener for the overlay view to catch the touch events. The idea was to catch the MotionEvent.ACTION_DOWN to avoid jumping to the fast scrollbar position. But following code does that already.
View scrollOverlay = (View)view.findViewById(R.id.scroll_overlay);
scrollOverlay.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return myListView.onTouchEvent(event);
}
});

Categories

Resources