Search code examples
androidanimationtextviewuigesturerecognizerontouchlistener

Highlight Textview onTouch


I'm trying implement something like in the gif image. Any suggestions how to do that? See image here I have set OnTouchListener to my parent layout which contains textviews. Detect the direction of the touch event. But I'm stuck on how to change background of the textviews continuously according to the finger swipe.

 <LinearLayout
       android:id="@+id/grades"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_marginTop="10dp"
       android:orientation="horizontal"
       android:weightSum="15">

        <TextView
           android:id="@+id/txt_1"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="1"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_2"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:gravity="center"
           android:padding="3dp"
           android:text="2"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_3"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="3"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_4"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="4"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_5"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="5"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_6"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="6"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_7"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="7"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_8"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="8"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_9"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="9"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_10"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="10"
           android:maxLines="1"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_11"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="11"
           android:maxLines="1"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_12"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="12"
           android:maxLines="1"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_13"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:padding="3dp"
           android:text="13"
           android:maxLines="1"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_14"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:maxLines="1"
           android:padding="3dp"
           android:text="14"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />

        <TextView
           android:id="@+id/txt_15"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:layout_marginLeft="2dp"
           android:layout_weight="1"
           android:background="@color/colorPrimary"
           android:maxLines="1"
           android:padding="3dp"
           android:text="15"
           android:textAlignment="center"
           android:textColor="@color/colorPrimaryDark" />


    </LinearLayout>

public class OnSwipeTouchListener implements OnTouchListener {

public final GestureDetector gestureDetector;
public OnSwipeTouchListener (Context ctx){
    gestureDetector = new GestureDetector(ctx, new GestureListener());
}

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    return false;
}

private final class GestureListener extends SimpleOnGestureListener {

    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        onSwipeRight();
                    } else {
                        onSwipeLeft();
                    }
                }
                result = true;
            }
            else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                if (diffY > 0) {
                    onSwipeBottom();
                } else {
                    onSwipeTop();
                }
            }
            result = true;

        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}

public void onSwipeRight() {
}

public void onSwipeLeft() {
}

public void onSwipeTop() {
}

public void onSwipeBottom() {
}}

public class ExamSubjectsActivity extends BaseActivity {
private ActivityExamsSubjectsBinding binding;

LinearLayout myLayout;
MotionEvent mMotionEvent;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_exams_subjects);
    myLayout = binding.grades;




    myLayout.setOnTouchListener(new OnSwipeTouchListener(this) {
        public void onSwipeTop() {
            Toast.makeText(ExamSubjectsActivity.this, "top", Toast.LENGTH_SHORT).show();

        }
        public void onSwipeRight() {
            Toast.makeText(ExamSubjectsActivity.this, "right", Toast.LENGTH_SHORT).show();
            for (int i = 0; i < myLayout.getChildCount(); i++) {

                View view = myLayout.getChildAt(i);
                Rect outRect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
                if (outRect.contains((int) mMotionEvent.getX(), (int) mMotionEvent.getY())) {
                    view.setBackgroundColor(ContextCompat.getColor(ExamSubjectsActivity.this, R.color.prime_orange));
                }

            }
        }
        public void onSwipeLeft() {
            Toast.makeText(ExamSubjectsActivity.this, "left", Toast.LENGTH_SHORT).show();
            for (int i = 0; i < myLayout.getChildCount(); i++) {

                View view = myLayout.getChildAt(i);
                Rect outRect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
                if (outRect.contains((int) mMotionEvent.getX(), (int) mMotionEvent.getY())) {
                    view.setBackgroundColor(ContextCompat.getColor(ExamSubjectsActivity.this, R.color.white));
                }

            }
        }
        public void onSwipeBottom() {
            Toast.makeText(ExamSubjectsActivity.this, "bottom", Toast.LENGTH_SHORT).show();
        }

        public boolean onTouch(View v, MotionEvent event) {

            return gestureDetector.onTouchEvent(event);
        }
    });


}

Solution

  • https://raw.githubusercontent.com/zhufeng1222/Image/master/textseekbar/demo.jpg

    create an object extends View to do this.

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.view.MotionEvent;
    import android.view.View;
    
    /**
     * Created by rajesh.zhu on 2017/9/27.
     */
    
    public class TextSeekBar extends View {
        private int padding = 3;
        private int mWidth = 0;
        private int mHeight = 0;
        private float rectWidth = 0F;
        private int totalIndex = 15;
        private int currentIndex = 0;
    
        private Paint normalPaint;
        private Paint selectPaint;
        private OnSeekBarChangeListener onSeekBarChangeListener;
    
        public TextSeekBar(Context context) {
            this(context, null);
        }
    
        public TextSeekBar(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public TextSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
        private void init(Context context) {
            DisplayMetrics metric = context.getResources().getDisplayMetrics();
            mWidth = metric.widthPixels;
    
            normalPaint = new Paint();
            normalPaint.setColor(0xFFFFFFFF);
            normalPaint.setTextSize(15);
            normalPaint.setAntiAlias(true);
            normalPaint.setTextAlign(Paint.Align.CENTER);
    
            selectPaint = new Paint();
            selectPaint.setColor(0xFFFD8900);
            selectPaint.setTextSize(15);
            selectPaint.setAntiAlias(true);
            selectPaint.setTextAlign(Paint.Align.CENTER);
        }
    
        @Override
        protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            rectWidth = (float) (mWidth) / (float) totalIndex;
            mHeight = (int) rectWidth;
            setMeasuredDimension(mWidth, mHeight);
        }
    
        @Override
        protected synchronized void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            for (int i = 0; i < totalIndex; i++) {
                int left = (int) (i * rectWidth) + padding;
                int top = padding;
                int right = (int) ((i + 1) * rectWidth) - padding;
                int bottom = mHeight - padding;
                Rect targetRect = new Rect(left, top, right, bottom);
    
                if (i <= currentIndex) {
                    canvas.drawRect(targetRect, selectPaint);
                    Paint.FontMetricsInt fontMetrics = normalPaint.getFontMetricsInt();
                    int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
                    canvas.drawText(String.valueOf(i + 1), targetRect.centerX(), baseline, normalPaint);
    
                } else {
                    canvas.drawRect(targetRect, normalPaint);
                    Paint.FontMetricsInt fontMetrics = selectPaint.getFontMetricsInt();
                    int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
                    canvas.drawText(String.valueOf(i + 1), targetRect.centerX(), baseline, selectPaint);
                }
            }
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    setCurrIndex(event);
                    if (onSeekBarChangeListener != null) {
                        onSeekBarChangeListener.onProgressStart(currentIndex + 1);
                    }
                    break;
                }
                case MotionEvent.ACTION_MOVE: {
                    setCurrIndex(event);
                    if (onSeekBarChangeListener != null) {
                        onSeekBarChangeListener.onProgressMoving(currentIndex + 1);
                    }
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    setCurrIndex(event);
                    if (onSeekBarChangeListener != null) {
                        onSeekBarChangeListener.onProgressChanged(currentIndex + 1);
                    }
                    break;
                }
            }
            return true;
        }
    
        private void setCurrIndex(MotionEvent event) {
            int downX = validPositionX((int) event.getX());
            currentIndex = downX / (int) rectWidth;
            invalidate();
        }
    
        private int validPositionX(int mDownX) {
            if (mDownX < 0) {
                mDownX = 0;
            }
            if (mDownX > mWidth) {
                mDownX = mWidth;
            }
            return mDownX;
        }
    
        public void setOnSeekBarChangeListener(OnSeekBarChangeListener onSeekBarChangeListener) {
            this.onSeekBarChangeListener = onSeekBarChangeListener;
        }
    
        public interface OnSeekBarChangeListener {
            void onProgressStart(int index);
    
            void onProgressMoving(int index);
    
            void onProgressChanged(int index);
        }
    }
    

    use this in Activity:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        infoTv = (TextView) findViewById(R.id.seek_info);
        seekBar = (TextSeekBar) findViewById(R.id.seek);
        seekBar.setOnSeekBarChangeListener(new TextSeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressStart(int index) {
                infoTv.setText(""+index);
            }
    
            @Override
            public void onProgressMoving(int index) {
                infoTv.setText(""+index);
            }
    
            @Override
            public void onProgressChanged(int index) {
                infoTv.setText(""+index);
            }
        });
    }
    

    here is the activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/seek_info"
            android:layout_width="match_parent"
            android:layout_height="44dp"
            android:layout_marginTop="40dp" />
    
        <com.rajesh.customcamera.view.TextSeekBar
            android:id="@+id/seek"
            android:layout_width="match_parent"
            android:layout_height="40dp" />
    
    </LinearLayout>