Android KeyBoard.Key disable iconPreview of special keys? - android

I customize my own soft keyboard by implementing the KeyboardView.OnKeyboardActionListener interface.
When the keys are pressed, it will show a preview popup.
My problem is how to disable the preview popup for special keys such as SHIFT and DELETE?
I have tried to set the android:iconPreview attribute to null but it didn't work.
<Key
android:codes="-1"
android:keyIcon="#drawable/key_shift"
android:keyWidth="15%p"
android:isModifier="true"
android:isSticky="true"
android:keyEdgeFlags="left" />
Have any idea?
Thanks in advance!

First you must implement OnKeyboardActionListener
then use onPress() and onRelease() to control the preview popup like this:
public void onPress(int primaryCode) {
if (primaryCode==-2||primaryCode==-5||primaryCode==-4){
mInputView.setPreviewEnabled(false);
}
}
public void onRelease(int primaryCode) {
mInputView.setPreviewEnabled(true);
}

public void onCreate() {
mInputView.setPreviewEnabled(false);
}
public void onPress(int primaryCode) {
if (primaryCode==-1||primaryCode==-2||primaryCode==-5||primaryCode==-4){
} else {
mInputView.setPreviewEnabled(true);
}
}
public void onRelease(int primaryCode) {
mInputView.setPreviewEnabled(false);
}

The problem with the above solution, as commented is that
if I press other key (e.g. key A) and move my finger to the key SHIFT, the preview icon still popup
To counter this, I had to extend the KeyboardView class
Disclaimer - The following contains reflection api
Here is the modified Keyboard class
import android.content.Context
import android.inputmethodservice.KeyboardView
import android.os.Build
import android.support.annotation.RequiresApi
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.TextView
import com.continental.testapplication.utils.dpToPx
import java.lang.reflect.Method
class ModifiedKeyboardView :KeyboardView{
constructor(context: Context, attrs: AttributeSet):super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr:Int):super(context, attrs, defStyleAttr)
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
constructor(context: Context, attrs: AttributeSet, defStyleAttr:Int, defStyleRes:Int):
super(context, attrs, defStyleAttr, defStyleRes)
/**
* Return true, if preview is to be shown, false otherwise. If not implemented,
* the preview is going to be shown.....
*/
var keyPreviewIndexListener:((Int)->Boolean) ?= null
private val findKeyIndicesMethod:Method = KeyboardView::class.java.getDeclaredMethod(
"getKeyIndices",Int::class.java,Int::class.java, (IntArray::class).java).also {
it.isAccessible = true
}
private val previewText:TextView = KeyboardView::class.java.getDeclaredField(
"mPreviewText").let {
it.isAccessible = true
it.get(this) as TextView
}
override fun onTouchEvent(me: MotionEvent?): Boolean {
if(me == null) return super.onTouchEvent(me)
when(me.action){
MotionEvent.ACTION_DOWN -> isPreviewEnabled = true
MotionEvent.ACTION_MOVE -> {
val touchX = me.x - paddingLeft
var touchY = me.y.toInt() - paddingTop
val verticalCorrection = dpToPx(14f, context)
if (touchY >= -verticalCorrection)
touchY += verticalCorrection.toInt()
val keyIndex:Int = findKeyIndicesMethod.invoke(this, touchX.toInt(), touchY.toInt(), null) as Int
isPreviewEnabled = keyPreviewIndexListener?.invoke(keyIndex)?:true
if(!isPreviewEnabled){
previewText.visibility = View.INVISIBLE
}
}
}
return super.onTouchEvent(me)
}
}
Paste it as is.
Next, in the class where you are manipulating the keyboard,
keyboardView.keyPreviewIndexListener = {
it != spaceIndex && it != doneIndex && it != deleteIndex && it != `your_custom_index`
}
To find the indexes you can just do the following
doneIndex = keyboardView.keyboard.keys.indexOfFirst {
it.codes[0] == Keyboard.KEYCODE_DONE
}
This will prevent the movement. Please append the other solution also.
i.e
override fun onPress(primaryCode: Int) {
Log.e("onPress", primaryCode.toString())
checkAndActivatePreview(primaryCode)
}
override fun onRelease(primaryCode: Int) {
Log.e("onRelease", primaryCode.toString())
deactivatePreview()
}
private fun checkAndActivatePreview(primaryCode: Int) {
keyboard.isPreviewEnabled =
(primaryCode != `your_custom_code`
&& primaryCode != SPACE_KEY_CODE && primaryCode != Keyboard.KEYCODE_DELETE
&& primaryCode != Keyboard.KEYCODE_DONE)
}

Related

Call requires API level 29 (current min is 21): `android.widget.NumberPicker#setTextColor`

I want to change selected field of text color using setTextColor. But Android Studio gives me this error. What should I do? Min SDK is 21.
This is code of my CustomNumberPicker class:
import android.annotation.TargetApi
import android.content.Context
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.NumberPicker
import android.widget.NumberPicker.OnScrollListener
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.widget.TextViewCompat
import ir.partsoftware.cup.R
import timber.log.Timber
class CustomNumberPicker : NumberPicker {
constructor(context: Context?) : super(context) {
init()
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
init()
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init()
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {
init()
}
private fun init() {
setDividerColor(ContextCompat.getColor(context, R.color.color_secondary))
setNumberPickerTextColor(this, ContextCompat.getColor(context, R.color.color_secondary))
this.setOnValueChangedListener { picker, oldVal, newVal ->
setNumberPickerTextColor(this, ContextCompat.getColor(context, R.color.color_secondary))
}
this.setOnScrollListener { numberPicker, scrollState ->
setNumberPickerTextColor(this, ContextCompat.getColor(context, R.color.color_secondary))
}
}
private fun setNumberPickerTextColor(numberPicker: NumberPicker, color: Int) {
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
numberPicker.textColor = color
} else {
val count = numberPicker.childCount
for (i in 0 until count) {
val child = numberPicker.getChildAt(i)
if (child is EditText) {
try {
child.setTextColor(color)
val fieldSelectorWheelPaint = numberPicker.javaClass.getDeclaredField("mSelectorWheelPaint")
val paint = fieldSelectorWheelPaint[numberPicker] as Paint
paint.color = color
fieldSelectorWheelPaint.isAccessible = true
numberPicker.invalidate()
} catch (ex: java.lang.Exception) {
// Ignore
}
}
}
}
}
private fun setDividerColor(#ColorInt color: Int) {
try {
val fDividerDrawable =
NumberPicker::class.java.getDeclaredField("mSelectionDivider")
fDividerDrawable.isAccessible = true
val d = fDividerDrawable[this] as Drawable
DrawableCompat.setTint(d, color)
d.invalidateSelf()
postInvalidate()
} catch (e: Exception) {
Timber.d(e)
}
}
override fun addView(
child: View,
index: Int,
params: ViewGroup.LayoutParams
) {
super.addView(child, index, params)
updateView(child)
}
private fun updateView(view: View) {
if (view is EditText) {
try {
TextViewCompat.setTextAppearance(view, R.style.TextAppearance_PartPay_NumPicker)
val customFont: Typeface? = ResourcesCompat.getFont(context, R.font.iran_yekan)
view.typeface = customFont
// setNumberPickerTextColor(ContextCompat.getColor(context, R.color.color_secondary))
} catch (e: Exception) {
Timber.d(e)
}
}
}
}
Try the next code. Will use reflection when the API is not accesible:
public void setNumberPickerTextColor(final NumberPicker numberPicker, final int color){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
numberPicker.setTextColor(color);
}
else {
final int count = numberPicker.getChildCount();
for (int i = 0; i < count; i++) {
final View child = numberPicker.getChildAt(i);
if (child instanceof EditText) {
try {
((EditText)child).setTextColor(color);
numberPicker.invalidate();
final Field fieldSelectorWheelPaint = numberPicker.getClass().getDeclaredField("mSelectorWheelPaint");
boolean isAccessible = fieldSelectorWheelPaint.isAccessible();
fieldSelectorWheelPaint.setAccessible(true);
final Paint paint = (Paint)fieldSelectorWheelPaint.get(numberPicker);
if (paint != null){
paint.setColor(color);
fieldSelectorWheelPaint.setAccessible(isAccessible);
numberPicker.invalidate();
}
final Field fieldSelectionDivider = numberPicker.getClass().getDeclaredField("mSelectionDivider");
isAccessible = fieldSelectionDivider.isAccessible();
fieldSelectionDivider.setAccessible(true);
fieldSelectionDivider.set(numberPicker, null);
fieldSelectionDivider.setAccessible(isAccessible);
numberPicker.invalidate();
}
catch (Exception ex) {
// Ignore
}
}
}
}
}
You may call this method the first time you get a reference to the control, and in addition if the color doesn't persist after scrolling, then hook listener such as next:
numberPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(final NumberPicker picker, final int oldVal, final int newVal) {
setNumberPickerTextColor(numberPicker, Color.RED);
}
});
Or alternatively you can also hook a scroll listener, although the above setOnValueChangedListener example is more optimal, as it will only perform the update when the value is changed. To improve the next scroll method you could check if the scrollState is in an idle state, so it is only called when scrolling ends:
numberPicker.setOnScrollListener(new NumberPicker.OnScrollListener() {
#Override
public void onScrollStateChange(final NumberPicker numberPicker, final int scrollState) {
setNumberPickerTextColor(numberPicker, Color.RED);
}
});
UPDATE:
The next section is specific only to your updated question code.
The problem is that you are extending a NumberPicker class, in such case you need to use the getDeclaredField on the super class. My above answer can be used only when not extending the NumberPicker class.
In addition you've placed the isAccesible in the wrong line, it needs to be a bit before to make it accesible.
Next is the correction to your code which can be used perfectly when extending a NumberPicker class. You can see that getDeclaredField is preceded by superclass, and isAccessible is at the correct position:
private fun setNumberPickerTextColor(numberPicker: NumberPicker, color: Int) {
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
numberPicker.textColor = color
} else {
val count = numberPicker.childCount
for (i in 0 until count) {
val child = numberPicker.getChildAt(i)
if (child is EditText) {
try {
child.setTextColor(color)
val fieldSelectorWheelPaint = numberPicker.javaClass.superclass.getDeclaredField("mSelectorWheelPaint")
fieldSelectorWheelPaint.isAccessible = true
val paint = fieldSelectorWheelPaint[numberPicker] as Paint
paint.color = color
numberPicker.invalidate()
} catch (ex: java.lang.Exception) {
// Ignore
}
}
}
}
}

Restrict user scrolling in RecyclerView

In my project I use a RecyclerView that I only want to scroll by calling the startSmoothScroll() method of the LayoutManager:
private fun next(){
val layoutManager = pager.layoutManager as BattlePageLayoutManager
layoutManager.startSmoothScroll(smoothScroller(layoutManager.findFirstVisibleItemPosition() + 1))
layoutManager.finishScroll()
}
I do not want the user to be able to scroll manually, e. g. by swiping.
I already tried to achieve this through overriding the method onInterceptTouchEvent() of the parent FrameLayout.
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
if (ev.actionMasked == MotionEvent.ACTION_DOWN){
startClickTime = System.currentTimeMillis()
startX = ev.x
startY = ev.y
}
val allowEvent = (System.currentTimeMillis() - startClickTime) < 1000 && (startX-ev.x).absoluteValue < 15 && (startY-ev.y).absoluteValue < 15
return !allowEvent
}
That worked basically, but it occured that after double-tapping the View users are able to scroll by themselves.
Do you have any other ideas to approach this?
Did you try overriding canScrollVertically() method in the LayoutManager?
mLayoutManager = new LinearLayoutManager(getActivity()) {
#Override
public boolean canScrollVertically() {
return false;
}
};
Edit:
Create your own implementation of RecyclerView which it disables the touch event while scrolling is performing. Then you have to change the RecyclerView class in the xml file and Fragment/Activity with it.
Find here an example in Kotlin
class MyRecyclerView : RecyclerView {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {}
override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
return if (scrollState != RecyclerView.SCROLL_STATE_IDLE) false else super.onInterceptTouchEvent(e)
}
}
And in Java
public class MyRecyclerView extends RecyclerView {
public MyRecyclerView(Context context) {
super(context);
}
public MyRecyclerView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if(getScrollState() != SCROLL_STATE_IDLE)
return false;
return super.onInterceptTouchEvent(e);
}
}
You might want to block the user interaction with RecyclerView, not with FrameLayout itself.
Check RecyclerView.OnItemTouchListener.
In your RecyclerView, you can implement OnItemTouchListener and override every method to do nothing.
That will block the user interaction with RecyclerView, making scroll not happen.

EditText has focus change event fired infinitely when changing compound drawable in focus listener

I have a custom edittext control which has a clear (x) icon set on the right when it's in focus and has text. Clicking the clear icon removes the text from the textbox. Unfortunately, when you click into the textbox, the focus change event is fired infinitely, as changing the compound drawable within the focus change listener seems to fire off two more focus change events, the first with the focus off, and the second with the focus back on. Any idea how I can get this working without the infinite loop?
Here is the code:
public class CustomEditText : EditText {
private Drawable clearButton;
protected CustomEditText (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {
}
public CustomEditText (Context context) : base (context) {
Init ();
}
public CustomEditText (Context context, IAttributeSet attrs) : base (context, attrs) {
Init (attrs);
}
public CustomEditText (Context context, IAttributeSet attrs, int defStyle) : base (context, attrs, defStyle) {
Init (attrs);
}
protected void Init (IAttributeSet attrs = null) {
// Set up clear button
SetupClearButton ();
SetupEvents ();
}
private void SetupClearButton () {
clearButton = ContextCompat.GetDrawable (Android.App.Application.Context, Resource.Drawable.forms_edit_text_clear_gray);
clearButton.SetBounds (0, 0, clearButton.IntrinsicWidth, clearButton.IntrinsicHeight);
}
private void SetupEvents () {
// Handle clear button visibility
this.TextChanged += (sender, e) => {
if (this.HasFocus)
UpdateClearButton ();
};
this.FocusChange += (object sender, FocusChangeEventArgs e) => {
UpdateClearButton (e.HasFocus);// Gets called infinitely
};
// Handle clearing the text
this.Touch += (sender, e) => {
if (this.GetCompoundDrawables ()[2] != null &&
e.Event.Action == MotionEventActions.Up &&
e.Event.GetX () > (this.Width - this.PaddingRight - clearButton.IntrinsicWidth)) {
this.Text = "";
UpdateClearButton ();
e.Handled = true;
} else
e.Handled = false;
};
}
private void UpdateClearButton (bool hasFocus = true) {
var compoundDrawables = this.GetCompoundDrawables ();
var compoundDrawable = this.Text.Length == 0 || !hasFocus ? null : clearButton;
if (compoundDrawables[2] != compoundDrawable)
this.SetCompoundDrawables (compoundDrawables[0], compoundDrawables[1], compoundDrawable, compoundDrawables[3]);
}
}
I ported DroidParts' ClearableEditText to Xamarin.Android to use when using the Android's Support Library widgets were not appropriate.
Note: DroidParts is under Apache 2.0 license so I can not post my C# derivative in full to StackOverflow, but the key to avoiding the continuous focus changing is in the OnTouch and OnFocusChange methods and the fact that the listeners are added to the base EditText Widget.
Full Code # https://gist.github.com/sushihangover/01a7965aae75d8ef0589697aa8f0e750
public bool OnTouch(View v, MotionEvent e)
{
if (GetDisplayedDrawable() != null)
{
int x = (int)e.GetX();
int y = (int)e.GetY();
int left = (loc == Location.LEFT) ? 0 : Width - PaddingRight - xD.IntrinsicWidth;
int right = (loc == Location.LEFT) ? PaddingLeft + xD.IntrinsicWidth : Width;
bool tappedX = x >= left && x <= right && y >= 0 && y <= (Bottom - Top);
if (tappedX)
{
if (e.Action == MotionEventActions.Up)
{
Text = "";
if (listener != null)
{
listener.DidClearText();
}
}
return true;
}
}
if (l != null)
return l.OnTouch(v, e);
return false;
}
public void OnFocusChange(View v, bool hasFocus)
{
if (hasFocus)
SetClearIconVisible(!string.IsNullOrEmpty(Text));
else
SetClearIconVisible(false);
if (f != null)
f.OnFocusChange(v, hasFocus);
}
Original StackOverflow Q/A: How to create EditText with cross(x) button at end of it?
In my opinion, the easiest implementation I have is this :
public class ClearableEditext : EditText
{
Context mContext;
Drawable imgX;
public ClearableEditext(Context context) : base(context)
{
init(context, null);
}
public ClearableEditext(Context context, Android.Util.IAttributeSet attrs) : base(context, attrs)
{
init(context, attrs);
}
public ClearableEditext(Context context, Android.Util.IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
init(context, attrs);
}
public ClearableEditext(Context context, Android.Util.IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
{
init(context, attrs);
}
public void init(Context ctx, Android.Util.IAttributeSet attrs)
{
mContext = ctx;
imgX = ContextCompat.GetDrawable(ctx, Android.Resource.Drawable.PresenceOffline);
imgX.SetBounds(0, 0, imgX.IntrinsicWidth, imgX.IntrinsicHeight);
manageClearButton();
this.SetOnTouchListener(new TouchHelper(this, imgX));
this.AddTextChangedListener(new TextListener(this));
}
public void manageClearButton()
{
if (this.Text.ToString().Equals(""))
removeClearButton();
else
addClearButton();
}
public void addClearButton()
{
this.SetCompoundDrawables(this.GetCompoundDrawables()[0],
this.GetCompoundDrawables()[1],
imgX,
this.GetCompoundDrawables()[3]);
}
public void removeClearButton()
{
this.SetCompoundDrawables(this.GetCompoundDrawables()[0],
this.GetCompoundDrawables()[1],
null,
this.GetCompoundDrawables()[3]);
}
}
public class TouchHelper : Java.Lang.Object, View.IOnTouchListener
{
ClearableEditext Editext;
public ClearableEditext objClearable { get; set; }
Drawable imgX;
public TouchHelper(ClearableEditext editext, Drawable imgx)
{
Editext = editext;
objClearable = objClearable;
imgX = imgx;
}
public bool OnTouch(View v, MotionEvent e)
{
ClearableEditext et = Editext;
if (et.GetCompoundDrawables()[2] == null)
return false;
// Only do this for up touches
if (e.Action != MotionEventActions.Up)
return false;
// Is touch on our clear button?
if (e.GetX() > et.Width - et.PaddingRight - imgX.IntrinsicWidth)
{
Editext.Text = string.Empty;
if (objClearable != null)
objClearable.removeClearButton();
}
return false;
}
}
public class TextListener : Java.Lang.Object, ITextWatcher
{
public ClearableEditext objClearable { get; set; }
public TextListener(ClearableEditext objRef)
{
objClearable = objRef;
}
public void AfterTextChanged(IEditable s)
{
}
public void BeforeTextChanged(ICharSequence s, int start, int count, int after)
{
}
public void OnTextChanged(ICharSequence s, int start, int before, int count)
{
if (objClearable != null)
objClearable.manageClearButton();
}
}
Probably Sushi has a better answer but i would suggest you to try this one out.
To change the x icon as your custom one change the image in init()

Make fragment clickable when navigation drawer is opened

My problem is as follows: I lock the navigation drawer menu setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN) in the landscape mode of the tablet, but I need the fragment from the right to be active, so I can click it with navigation always opened. But I dont know how to do it. Please help.
There are a few things you need to do:
Disable the layout fading by setting a transparent color:
drawer.setScrimColor(Color.TRANSPARENT);
Lock the drawer
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
Create a custom drawer class which allows clicking through when in locked mode:
public class CustomDrawer extends DrawerLayout {
public CustomDrawer(Context context) {
super(context);
}
public CustomDrawer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
View drawer = getChildAt(1);
if (getDrawerLockMode(drawer) == LOCK_MODE_LOCKED_OPEN && ev.getRawX() > drawer.getWidth()) {
return false;
} else {
return super.onInterceptTouchEvent(ev);
}
}
}
Use this class in xml:
<com.example.myapplication.CustomDrawer
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
</FrameLayout>
<ListView android:layout_width="100dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"/>
</com.example.myapplication.CustomDrawer>
This is a tricky one. When the drawer is open, it intercepts your touch events which trigger the close of the drawer. In order to prevent that, you need to subclass your DrawerLayout and override the onInterceptTouchEvent method:
public class CustomDrawerLayout extends DrawerLayout
{
private View rightView;
private int mTouchSlop;
public CustomDrawerLayout (Context context)
{
this(context, null);
}
public CustomDrawerLayout (Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public CustomDrawerLayout (Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(ViewConfiguration.get(context));
}
public void setRightView (View v)
{
this.rightView = v;
}
#Override
public boolean onInterceptTouchEvent (MotionEvent ev)
{
boolean result = super.onInterceptTouchEvent(ev);
if (rightView != null && isDrawerOpen(rightView))
{
DrawerLayout.LayoutParams layoutParams = (DrawerLayout.LayoutParams) rightView.getLayoutParams();
if (layoutParams.gravity == Gravity.END)
{
// This is true when the position.x of the event is happening on the left of the drawer (with gravity END)
if (ev.getX() < rightView.getX() && ev.getX() > mTouchSlop)
{
result = false;
}
}
}
return result;
}
}
This is my code working with a right drawer. I'm sure you can adapt this for your left drawer. You might also want to disable the shadow:
mDrawerLayout.setScrimColor(Color.TRANSPARENT);
Thanks for #Simas's solution!
I found if an item which user click is quite near drawerView, use ev.rawX is not appropriate. Furthermore, I add other gravity check to determinate interception.
class ContentTouchableDrawer #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : DrawerLayout(context, attrs) {
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
val drawer: View = getChildAt(1)
logt("drawer : $drawer")
logt("drawer : width = ${drawer.width}")
logt("drawer : x = ${drawer.x}")
logt("drawer : eventRawX = ${ev.rawX}")
logt("drawer : eventX = ${ev.x}")
val drawerGravity = (drawer.layoutParams as LayoutParams).gravity
val result = when(drawerGravity){
Gravity.RIGHT, GravityCompat.END -> ev.x < drawer.x
Gravity.LEFT, GravityCompat.START -> ev.x > drawer.width
//Gravity.NO_GRAVITY
else -> false
}
return if (getDrawerLockMode(drawer) == LOCK_MODE_LOCKED_OPEN && result) {
false
} else {
super.onInterceptTouchEvent(ev)
}
}
}

Android: Remove only bottom FadingEdge effect from scroll bar

I know how to disable fadingedge from scrollbar but what I need is to disable just the bottom fading edge without disabling the top fading edge effect, is that possible?
You can achieve the effect you want by extending the ScrollView and overriding one of those two methods:
float getTopFadingEdgeStrength()
float getBottomFadingEdgeStrength()
They'll alow you to change the size of the fading edge - just set bottom value to 0 and you are ready to go :)
Code example with bottom fading turned off:
/**
* Created by scana on 14.12.14.
*/
public class TopFadeEdgeScrollView extends ScrollView {
public TopFadeEdgeScrollView(Context context) {
super(context);
}
public TopFadeEdgeScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TopFadeEdgeScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected float getBottomFadingEdgeStrength() {
return 0.0f;
}
}
scana's answer is correct.
Here's a Kotlin version of his answer that has methods to disable specific edges.
import android.content.Context
import android.util.AttributeSet
import android.widget.ScrollView
class FadingEdgeScrollView #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : ScrollView(context, attrs, defStyle) {
var topFadingStrength: Float? = null
var bottomFadingStrength: Float? = null
var leftFadingStrength: Float? = null
var rightFadingStrength: Float? = null
override fun getTopFadingEdgeStrength(): Float {
return topFadingStrength ?: super.getTopFadingEdgeStrength()
}
override fun getBottomFadingEdgeStrength(): Float {
return bottomFadingStrength ?: super.getBottomFadingEdgeStrength()
}
override fun getLeftFadingEdgeStrength(): Float {
return leftFadingStrength ?: super.getLeftFadingEdgeStrength()
}
override fun getRightFadingEdgeStrength(): Float {
return rightFadingStrength ?: super.getRightFadingEdgeStrength()
}
fun disableTopFade() {
topFadingStrength = 0f
}
fun disableBottomFade() {
bottomFadingStrength = 0f
}
fun disableLeftFade() {
leftFadingStrength = 0f
}
fun disableRightFade() {
rightFadingStrength = 0f
}
}

Categories

Resources