I need to customize default android seekbar to control music player. I know this sounds very simple, but I just don't know how to set up seekbar thumb listener. I want to control music and change icon accordingly to play and pause when user press on seekbar thumb icon. How can I achieve this? I know that this is possible because I previously saw apps like PocketGuide where this functionality is implemented. Here's the screenshot from PocketGuide app
Maybe this helps you. Adjust the code for your needs.
public class SeekbarWithThumbTouch extends SeekBar {
private int scaledTouchSlop = 0;
private float initTouchX = 0;
private boolean thumbPressed = false;
public SeekbarWithThumbTouch(Context context) {
super(context);
init(context);
}
public SeekbarWithThumbTouch(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SeekbarWithThumbTouch(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Drawable thumb = null;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
thumb = getThumb();//works only for API >=16!
if (thumb != null) {
//contains current position of thumb in view as bounds
RectF bounds = new RectF(thumb.getBounds());
thumbPressed = bounds.contains(event.getX(), event.getY());
if (thumbPressed) {
Log.d("Thumb", "pressed");
initTouchX = event.getX();
return true;
}
}
break;
case MotionEvent.ACTION_UP:
if (thumbPressed) {
Log.d("Thumb", "was pressed -- listener call");
thumbPressed = false;
}
break;
case MotionEvent.ACTION_MOVE:
if (thumbPressed) {
if (Math.abs(initTouchX - event.getX()) > scaledTouchSlop) {
initTouchX = 0;
thumbPressed = false;
return super.onTouchEvent(event);
}
Log.d("Thumb", "move blocked");
return true;
}
break;
}
return super.onTouchEvent(event);
}
}
Related
I am working on a text editor for a programming language, it has two parts, the line number box (2) and the code box (1) like in the figure below
..................
. . .
. . .
. 2. 1 .
. . .
. . .
. . .
..................
If the user clicks in the line number box (2), I need to execute some code, here I just show a toast with the message 'Click' but ignoure the default behavior of edit text.
If the user clicks inside box 1, just delegate the default edittext behavior by calling super.onTouchEvent(event).
Here's what I did, but I don't know how to get it to work properly, i need to play with the return value of onTouchEvent:
public class MyEditText extends AppCompatEditText {
private Rect drawingBound;
private Rect leftRect; // area 2
private Paint rectPaint;
private static final int PADDING = 100;
private boolean down = false;
public MyEditText(#NonNull Context context) {
super(context);
init(context);
}
public MyEditText(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyEditText(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
setPadding(PADDING, 0, 0, 0);
drawingBound = new Rect();
leftRect = new Rect();
rectPaint = new Paint();
rectPaint.setColor(Color.GREEN);
rectPaint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
getDrawingRect(drawingBound);
leftRect.set(drawingBound);
leftRect.right = drawingBound.left+ PADDING;
canvas.drawRect(leftRect, rectPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
down = true;
return false;
}
else if (action == MotionEvent.ACTION_UP) {
if (down) {
down = false;
int x = (int) event.getX();
int y = (int) event.getY();
if (leftRect.contains(x, y)) {
Toast.makeText(getContext(), "Click", Toast.LENGTH_SHORT).show();
return true;
}
}
return super.onTouchEvent(event);
} else {
return super.onTouchEvent(event);
}
}
}
I'm coding an ebook reader.
For paging I had the smart (stupid ?) idea to use a custom WebView. I changed it's behavior and it scrolls down of 1 page when I swipe left. It works really good expect on one point... The top and bottom text are often cut off. I got the height of my WebView and my font size but then I don't know what to do with that... Is there a way to have no cut off text at the top and at the bottom of my WebView ? It looks like they used the same same technic but with a ScrollView in the opensource PageTurner app but the code is quite complicated, I can't get the code part who could be interesting for me.
public class BookWebView extends WebView {
private final String LOG_TAG = BookView.class.getSimpleName();
private final int SWIPE_LIMIT = 80;
private float startX,diffX;
public BookWebView(Context context) {
super(context);
}
public BookWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BookWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
break;
case MotionEvent.ACTION_UP:
if(Math.abs(diffX) > SWIPE_LIMIT) {
int visibleTextHeight = this.getHeight();
if(diffX < 0) {
Log.d(LOG_TAG,"SCROLLING DOWN");
this.scrollTo(0, getScrollY() + visibleTextHeight);
} else {
Log.d(LOG_TAG,"SCROLLING UP");
this.scrollTo(0, getScrollY() - visibleTextHeight);
}
} else {
Log.d(LOG_TAG, "==== NO SCROLL ====");
return false;
}
break;
case MotionEvent.ACTION_MOVE:
float endX = event.getX();
diffX = endX - startX;
break;
case MotionEvent.ACTION_POINTER_UP:
break;
}
return true;
}
}
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BookWebView bwvText = (BookWebView)findViewById(R.id.bwv_text);
String text = "<html><body style=\"text-align:justify\"> %s </body></Html>";
bwvText.loadData(String.format(text,getString(R.string.lorem_ipsum)),"text/html; charset=utf-8", "utf-8");
WebSettings webSettings = bwvText.getSettings();
int fontSize = webSettings.getDefaultFontSize();
bwvText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
bwvText.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
bwvText.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
int webViewHeight = bwvText.getMeasuredHeight();
adjustHeight(webViewHeight,fontSize);
}
});
}
private void adjustHeight(int webViewHeight, int fontSize) {
// Is there something I can do here ?
}
activity_main.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.android.severalpagestext.MainActivity">
<com.example.android.severalpagestext.BookWebView
android:id="#+id/bwv_text"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
enter code here i am using recyclerview but i need to implement one more
recyclerview inside the adapter layout of the recyclerview. Can
anyone tell me how can i set the json data to the recyclerview
which is inside the cardview of verticsal recycler. Dont tell me
about how to set the horizontal recyclerview i know it very well.
the problem with me is that i am confused that how to set data to
recyclerview which is inside cardview of vertical recyclerview
You can pass a List> to the vertical RecyclerView's adapter and then in the onBindViewHolder, pass the inner list at some index i to the constructor of horizontal RecyclerView's adapter.
For the outer vertical RecyclerView, use this extended class:
public class BetterRecyclerView extends RecyclerView{
private static final int INVALID_POINTER = -1;
private int mScrollPointerId = INVALID_POINTER;
private int mInitialTouchX, mInitialTouchY;
private int mTouchSlop;
public BetterRecyclerView(Context context) {
this(context, null);
}
public BetterRecyclerView(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BetterRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final ViewConfiguration vc = ViewConfiguration.get(getContext());
mTouchSlop = vc.getScaledTouchSlop();
}
#Override
public void setScrollingTouchSlop(int slopConstant) {
super.setScrollingTouchSlop(slopConstant);
final ViewConfiguration vc = ViewConfiguration.get(getContext());
switch (slopConstant) {
case TOUCH_SLOP_DEFAULT:
mTouchSlop = vc.getScaledTouchSlop();
break;
case TOUCH_SLOP_PAGING:
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(vc);
break;
default:
break;
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent e) {
final int action = MotionEventCompat.getActionMasked(e);
final int actionIndex = MotionEventCompat.getActionIndex(e);
switch (action) {
case MotionEvent.ACTION_DOWN:
mScrollPointerId = MotionEventCompat.getPointerId(e, 0);
mInitialTouchX = (int) (e.getX() + 0.5f);
mInitialTouchY = (int) (e.getY() + 0.5f);
return super.onInterceptTouchEvent(e);
case MotionEventCompat.ACTION_POINTER_DOWN:
mScrollPointerId = MotionEventCompat.getPointerId(e, actionIndex);
mInitialTouchX = (int) (MotionEventCompat.getX(e, actionIndex) + 0.5f);
mInitialTouchY = (int) (MotionEventCompat.getY(e, actionIndex) + 0.5f);
return super.onInterceptTouchEvent(e);
case MotionEvent.ACTION_MOVE: {
final int index = MotionEventCompat.findPointerIndex(e, mScrollPointerId);
if (index < 0) {
return false;
}
final int x = (int) (MotionEventCompat.getX(e, index) + 0.5f);
final int y = (int) (MotionEventCompat.getY(e, index) + 0.5f);
if (getScrollState() != SCROLL_STATE_DRAGGING) {
final int dx = x - mInitialTouchX;
final int dy = y - mInitialTouchY;
final boolean canScrollHorizontally = getLayoutManager().canScrollHorizontally();
final boolean canScrollVertically = getLayoutManager().canScrollVertically();
boolean startScroll = false;
if (canScrollHorizontally && Math.abs(dx) > mTouchSlop && (Math.abs(dx) >= Math.abs(dy) || canScrollVertically)) {
startScroll = true;
}
if (canScrollVertically && Math.abs(dy) > mTouchSlop && (Math.abs(dy) >= Math.abs(dx) || canScrollHorizontally)) {
startScroll = true;
}
return startScroll && super.onInterceptTouchEvent(e);
}
return super.onInterceptTouchEvent(e);
}
default:
return super.onInterceptTouchEvent(e);
}
}
}
For the inner horizontal RecyclerView, use this extended class:
public class FeedRootRecyclerView extends BetterRecyclerView{
public FeedRootRecyclerView(Context context) {
this(context, null);
}
public FeedRootRecyclerView(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public FeedRootRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
/* do nothing */
}
}
You can find proper explanation as to what these classes do over here : http://nerds.headout.com/fix-horizontal-scrolling-in-your-android-app/
I have an ImageView in a FrameLayout, I want to setup LongClickListener but its failing to work, I tried setting up OnTouchListener and its working flawless, I do not have the slightest idea as to why its not working but below is my code code:
public class DragImageView extends FrameLayout implements View.OnLongClickListener {
ImageView ivDrag;
public DragImageView(Context context) {
super(context);
}
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DragImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void AddImageView(View draggableObject, int x, int y, int width, int height) {
LayoutParams lpDraggableView = new LayoutParams(width, height);
lpDraggableView.gravity = Gravity.TOP;
lpDraggableView.leftMargin = x;
lpDraggableView.topMargin = y;
if(draggableObject instanceof ImageView) {
this.ivDrag = (ImageView) draggableObject;
ivDrag.setLayoutParams(lpDraggableView);
ivDrag.setClickable(true);
ivDrag.setLongClickable(true);
ivDrag.setOnLongClickListener(this);
this.addView(ivDrag);
}
}
/**
* Draggable object ontouch listener
* Handle the movement of the object when dragged and dropped
*/
private View.OnTouchListener OnTouchToDrag =new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
FrameLayout.LayoutParams dragParam = (LayoutParams) v.getLayoutParams();
switch(event.getAction())
{
case MotionEvent.ACTION_MOVE:
{
dragParam.topMargin = (int)event.getRawY() - (v.getHeight());
dragParam.leftMargin = (int)event.getRawX() - (v.getWidth()/2);
v.setLayoutParams(dragParam);
break;
}
case MotionEvent.ACTION_UP:
{
dragParam.height = v.getHeight();
dragParam.width = v.getWidth();
dragParam.topMargin = (int)event.getRawY() - (v.getHeight());
dragParam.leftMargin = (int)event.getRawX() - (v.getWidth()/2);
v.setLayoutParams(dragParam);
break;
}
case MotionEvent.ACTION_DOWN:
{
dragParam.height = v.getHeight();//fixed on drag and drop
dragParam.width = v.getWidth();
v.setLayoutParams(dragParam);
break;
}
}
return true;
}
};
#Override
public boolean onLongClick(View view) {
ivDrag.setOnTouchListener(OnTouchToDrag);
Toast.makeText(view.getContext(), "OnLongClick", Toast.LENGTH_SHORT).show();
return false;
}
}
I want to setup LongClickListener but its failing to work
You are not receiving the callbacks from OnLongClickListener because it has no set listener. Since your class implements View.OnLongClickListener and you want to receive the callback in your overridden onLongClick() method, add this class itself as the listener and it will work. I've done so in the constructor (choose the appropriate constructor out of the three as per your initialization of the view):
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOnLongClickListener(this); // <-- set this class instance as the listener
}
Although I'm surprised how you got it working with OnTouchListener. You probably explicitly added the listener, right?
i just read this How can I add an image on EditText and want to know if it is possible to add action on the icon when clicked...
yes it's possible just create CustomEediTtext extends from EditText. check this solution
Create a customized EditText class CustomEditText.java:
public class CustomEditText extends EditText {
private Drawable dRight;
private Rect rBounds;
public CustomEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomEditText(Context context) {
super(context);
}
#Override
public void setCompoundDrawables(Drawable left, Drawable top,
Drawable right, Drawable bottom) {
if(right !=null)
{
dRight = right;
}
super.setCompoundDrawables(left, top, right, bottom);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP && dRight!=null) {
rBounds = dRight.getBounds();
final int x = (int)event.getX();
final int y = (int)event.getY();
if(x>=(this.getRight()-rBounds.width()) && x<=(this.getRight()-
this.getPaddingRight()) && y>=this.getPaddingTop() && y<=(this.getHeight()-
this.getPaddingBottom())) {
//System.out.println("touch");
this.setText("");
event.setAction(MotionEvent.ACTION_CANCEL);//use this to prevent the keyboard
}
}
return super.onTouchEvent(event);
}
#Override
protected void finalize() throws Throwable {
dRight = null;
rBounds = null;
super.finalize();
}
}