I've created a custom range seek bar and I would like to implement accessibility for it. The normal gesture to move the ball to the right/up in the default seek bar is "Right then left". So when the user has the focus on the left ball I want to detect the "Right then left" gesture when the talkback is on and move the ball one step.
You can activate the talkback and use the volume as an example of what I'm trying to achieve.
Talkback gestures information:
URL
public class MyRangeSeekBar extends ConstraintLayout implements View.OnTouchListener {
private static final String TAG = MyRangeSeekBar.class.getSimpleName();
private static final long BALL_SPEED = 300;
private static final int STEPS_LIMIT = 2;
private static final int STEPS_MAX = 10;
private final MyRangeSeekBarBinding binding;
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.ENGLISH);
private int min = 1;
private int max = 10;
private int currentMin = 1;
private int currentMax = 10;
private float dX;
private float posInitBar;
private float posEndBar;
private float halfBallWidth;
private float barWidth;
private float segmentWidth;
private int rangeDescriptionLabel;
private int rangeJoinDescriptionLabel;
private int minimumDescriptionLabel;
private int maximumDescriptionLabel;
private DecimalFormat df = new DecimalFormat("#.##", symbols);
public MyRangeSeekBar(Context context) {
this(context, null);
}
public MyRangeSeekBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyRangeSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
binding = MyRangeSeekBarBinding.inflate(inflater, this, true);
initAttrs(context, attrs, defStyleAttr);
}
private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
final TypedArray attributes =
context.obtainStyledAttributes(
attrs,
R.styleable.MyRangeSeekBar,
defStyleAttr,
0);
min = attributes.getInt(R.styleable.MyRangeSeekBar_min, 1);
max = attributes.getInt(R.styleable.MyRangeSeekBar_max, 10);
currentMin = attributes.getInt(R.styleable.MyRangeSeekBar_currentMin, 1);
currentMax = attributes.getInt(R.styleable.MyRangeSeekBar_currentMax, 10);
rangeDescriptionLabel = attributes.getResourceId(R.styleable.MyRangeSeekBar_rangeDescriptionLabel, R.string.mcaiucomps_range_label);
rangeJoinDescriptionLabel = attributes.getResourceId(R.styleable.MyRangeSeekBar_rangeJoinDescriptionLabel, R.string.mcaiucomps_range_join_label);
minimumDescriptionLabel = attributes.getResourceId(R.styleable.MyRangeSeekBar_minimumDescriptionLabel, R.string.mcaiucomps_min_label);
maximumDescriptionLabel = attributes.getResourceId(R.styleable.MyRangeSeekBar_maximumDescriptionLabel, R.string.mcaiucomps_max_label);
attributes.recycle();
refresh();
}
private void checkValues() {
if (max - min < STEPS_LIMIT) {
throw new RuntimeException("Not enough steps, you need a minimum of 2 steps like from 1 to 3");
}
if (max - min >= STEPS_MAX) {
throw new RuntimeException("Too many steps, you can't do more than 10 steps");
}
if (currentMin < min || currentMin > max) {
throw new RuntimeException("The minimum value is not between the limits");
}
if (currentMax < min || currentMax > max) {
throw new RuntimeException("The maximum value is not between the limits");
}
if (currentMin > currentMax) {
throw new RuntimeException("The minimum is bigger than the maximum value");
}
}
private void setBar() {
binding.mcaiucompsBar.post(new Runnable() {
#Override
public void run() {
halfBallWidth = binding.mcaiucompsBallLeft.getMeasuredWidth() / 2;
posInitBar = binding.mcaiucompsBar.getX() + halfBallWidth;
posEndBar = binding.mcaiucompsBar.getMeasuredWidth() - halfBallWidth;
binding.mcaiucompsBallRight.setX(posEndBar + halfBallWidth);
binding.mcaiucompsBallLeft.setX(posInitBar + halfBallWidth);
barWidth = posEndBar - posInitBar;
segmentWidth = barWidth / (max - min);
setBalls();
}
});
}
private void setTitles() {
binding.mcaiucompsMinValue.setText(getContext().getString(minimumDescriptionLabel, min));
binding.mcaiucompsMinValue.setContentDescription(getContext().getString(minimumDescriptionLabel, min) + ", " + getContext().getString(R.string.caixabank_componente_rango_minimo));
binding.mcaiucompsMaxValue.setText(getContext().getString(maximumDescriptionLabel, max));
binding.mcaiucompsMaxValue.setContentDescription(getContext().getString(maximumDescriptionLabel, max) + ", " + getContext().getString(R.string.caixabank_componente_rango_maximo));
binding.mcaiucompsTitle.setText(getContext().getString(rangeDescriptionLabel, currentMin, currentMax));
binding.mcaiucompsTitle.setContentDescription(getContext().getString(rangeDescriptionLabel, currentMin, currentMax));
}
private void updateBallsPosition(View view) {
//Check limits
if (binding.mcaiucompsBallLeft.getId() == view.getId() && getLeftBallPos() < posInitBar) {
animateBall(view, posInitBar);
} else if (binding.mcaiucompsBallRight.getId() == view.getId() && getRightBallPos() > posEndBar) {
animateBall(view, posEndBar);
} else {
//Move to the closest position
if (view.getId() == binding.mcaiucompsBallLeft.getId()) {
if (getLeftBallPos() >= posInitBar) {
currentMin = Math.round(getLeftBallPos() / segmentWidth);
} else if (getLeftBallPos() >= getRightBallPos()) {
currentMin = currentMax;
} else {
currentMin = min;
}
animateBall(binding.mcaiucompsBallLeft, currentMin * segmentWidth + posInitBar);
} else {
if (getRightBallPos() < barWidth) {
currentMax = Math.round(getRightBallPos() / segmentWidth);
} else if (getRightBallPos() >= getLeftBallPos()) {
currentMax = currentMin;
} else {
currentMax = max - min;
}
animateBall(binding.mcaiucompsBallRight, currentMax * segmentWidth + posInitBar);
}
}
}
private void animateBall(View view, float pos) {
pos = Float.parseFloat(df.format(pos));
// Leave some space between balls if they are in the same position
if (view.getId() == binding.mcaiucompsBallLeft.getId()
&& (pos <= getRightBallPos() && pos >= getRightBallPos() - halfBallWidth || pos >= posEndBar)) {
binding.mcaiucompsBallLeft.animate()
.x(getRightBallPos() - halfBallWidth * 1.7f)
.setDuration(BALL_SPEED)
.setInterpolator(new DecelerateInterpolator())
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
changeBarHighlightSize();
updateTitle();
}
})
.start();
} else if (view.getId() == binding.mcaiucompsBallRight.getId()
&& (pos >= getLeftBallPos() && pos <= getLeftBallPos() + halfBallWidth || pos <= posInitBar)) {
binding.mcaiucompsBallRight.animate()
.x(getLeftBallPos() - halfBallWidth * 0.3f)
.setDuration(BALL_SPEED)
.setInterpolator(new DecelerateInterpolator())
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
changeBarHighlightSize();
updateTitle();
}
})
.start();
} else {
view.animate()
.x(pos - halfBallWidth)
.setDuration(BALL_SPEED)
.setInterpolator(new DecelerateInterpolator())
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
changeBarHighlightSize();
updateTitle();
}
})
.start();
}
}
private void updateTitle() {
int minLabel = Math.round((getLeftBallPos() - posInitBar) / segmentWidth) + min;
int maxLabel = Math.round((getRightBallPos() - posInitBar) / segmentWidth) + min;
if (getRightBallPos() == posEndBar || maxLabel > max) {
maxLabel = max;
}
if (getLeftBallPos() == posInitBar || minLabel < min) {
minLabel = min;
}
String title = getContext().getString(rangeDescriptionLabel, minLabel, maxLabel);
if (minLabel == maxLabel) {
title = getContext().getString(rangeJoinDescriptionLabel, minLabel);
}
binding.mcaiucompsTitle.setText(title);
binding.mcaiucompsTitle.setContentDescription(title);
}
private float getLeftBallPos() {
return Float.parseFloat(df.format(binding.mcaiucompsBallLeft.getX() + halfBallWidth));
}
private float getRightBallPos() {
return Float.parseFloat(df.format(binding.mcaiucompsBallRight.getX() + halfBallWidth));
}
private void setBalls() {
binding.mcaiucompsBallLeft.setOnTouchListener(this);
binding.mcaiucompsBallRight.setOnTouchListener(this);
float posMin = (currentMin - min) * segmentWidth + posInitBar;
float posMax = (currentMax - min) * segmentWidth + posInitBar;
if (currentMax == currentMin) {
posMin = posMax + halfBallWidth - halfBallWidth * 1.7f;
}
animateBall(binding.mcaiucompsBallLeft, posMin);
animateBall(binding.mcaiucompsBallRight, posMax);
}
#Override
public boolean onTouch(View view, MotionEvent event) {
if (binding.mcaiucompsBallLeft.getId() == view.getId()
|| binding.mcaiucompsBallRight.getId() == view.getId()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dX = view.getX() - event.getRawX();
view.bringToFront();
break;
case MotionEvent.ACTION_MOVE:
if (isValidMove(view, event.getRawX() + dX)) {
view.animate()
.x(event.getRawX() + dX)
.setDuration(0)
.start();
changeBarHighlightSize();
updateTitle();
Log.d(TAG, "onTouch: " + event.getRawX() + " dx: " + dX);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
updateBallsPosition(view);
break;
default:
return false;
}
return true;
}
return false;
}
private boolean isValidMove(View view, float rawX) {
if ((binding.mcaiucompsBallLeft.getId() == view.getId() && getLeftBallPos() >= posInitBar)
|| (binding.mcaiucompsBallRight.getId() == view.getId() && getRightBallPos() <= posEndBar)) {
if ((binding.mcaiucompsBallLeft.getId() == view.getId() && rawX + halfBallWidth / 2 <= binding.mcaiucompsBallRight.getX())
|| (binding.mcaiucompsBallRight.getId() == view.getId() && rawX + halfBallWidth / 2 >= getLeftBallPos())) {
return true;
}
}
return false;
}
public void changeBarHighlightSize() {
ViewGroup.LayoutParams params = binding.mcaiucompsBarHighlight.getLayoutParams();
params.width = (int) (getRightBallPos() - getLeftBallPos());
binding.mcaiucompsBarHighlight.setLayoutParams(params);
binding.mcaiucompsBarHighlight.setX(getLeftBallPos());
}
public int getMin() {
return min;
}
public void setMin(int min) {
this.min = min;
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getCurrentMin() {
return currentMin;
}
public void setCurrentMin(int currentMin) {
this.currentMin = currentMin;
}
public int getCurrentMax() {
return currentMax;
}
public void setCurrentMax(int currentMax) {
this.currentMax = currentMax;
}
public void setRangeDescriptionLabel(#StringRes int rangeDescriptionLabel) {
this.rangeDescriptionLabel = rangeDescriptionLabel;
updateTitle();
}
public void setRangeJoinDescriptionLabel(#StringRes int rangeJoinDescriptionLabel) {
this.rangeJoinDescriptionLabel = rangeJoinDescriptionLabel;
updateTitle();
}
public void setMinimumDescriptionLabel(#StringRes int minimumDescriptionLabel) {
this.minimumDescriptionLabel = minimumDescriptionLabel;
setTitles();
}
public void setMaximumDescriptionLabel(#StringRes int maximumDescriptionLabel) {
this.maximumDescriptionLabel = maximumDescriptionLabel;
setTitles();
}
public void refresh() {
checkValues();
setBar();
setTitles();
}
#Override
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
return super.onRequestSendAccessibilityEvent(child, event);
}
}
Thanks!
Related
I am Using SelectableTextview in my e-book app where i want to highlight any text from the book. The text is being highlighted by SelectableTextViewer class, and i am saving the selected text in database. Now i want when the user open the e-book next time the same text should be highlighted as it is. But there is no method of setting selected text. How can i solve this problem. Please help me
SelectableTextviewer.java
public class SelectableTextViewer extends RelativeLayout {
private ImageView imgStartSelect;
public static int mStartSelect = -1;
private ImageView imgEndSelect;
public static int mEndSelect = -1;
private int mImgWidth = 40;
private int mImgHeight = 50;
private TextView textView;
private View mCurrentControlFocused;
public static interface ISelectableTextViewerListener {
public void updateSelection(SelectableTextViewer selectableTextViewer);
public void endSelectingText(SelectableTextViewer selectableTextViewer,
String selectedText);
public void stopSelectingText(
SelectableTextViewer selectableTextViewer, String selectedText);
}
private ISelectableTextViewerListener selectableTextViewerListener;
public static BackgroundColorSpan spanBackgroundColored;
public void setSelectableTextViewerListener(
ISelectableTextViewerListener selectableTextViewerListener) {
this.selectableTextViewerListener = selectableTextViewerListener;
}
public SelectableTextViewer(Context context) {
super(context);
if (!isInEditMode()) {
this.initControls();
}
}
public SelectableTextViewer(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode()) {
this.initControls();
}
}
public SelectableTextViewer(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
if (!isInEditMode()) {
this.initControls();
}
}
private void initControls() {
this.spanBackgroundColored = new BackgroundColorSpan(Color.YELLOW);
this.textView = new TextView(getContext());
this.addView(textView);
this.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
showSelectionControls();
int[] location = { 0, 0 };
getLocationOnScreen(location);
System.out.println("getLocationOnScreen:" + location[0] + "\t"
+ location[1]);
return false;
}
});
this.createImgControllersForSelection();
}
protected void disallowIntercept(Boolean disallowIntercept) {
this.getParent().requestDisallowInterceptTouchEvent(disallowIntercept);
}
protected void createImgControllersForSelection() {
this.imgStartSelect = new ImageView(getContext());
this.imgEndSelect = new ImageView(getContext());
this.imgStartSelect.setImageResource(R.drawable.cursor);
this.imgEndSelect.setImageResource(R.drawable.cursor);
this.addView(imgStartSelect, mImgWidth, mImgHeight);
this.addView(imgEndSelect, mImgWidth, mImgHeight);
OnClickListener onClickForChangeFocus = new OnClickListener() {
#Override
public void onClick(View v) {
mCurrentControlFocused = v;
}
};
this.imgEndSelect.setOnClickListener(onClickForChangeFocus);
this.imgStartSelect.setOnClickListener(onClickForChangeFocus);
OnTouchListener onTouchSelectionControl = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
disallowIntercept(true);
mCurrentControlFocused = v;
int eid = event.getAction();
switch (eid) {
case MotionEvent.ACTION_MOVE:
int[] location = { 0, 0 };
getLocationOnScreen(location);
LayoutParams mParams = (LayoutParams) v
.getLayoutParams();
int x = (int) event.getRawX();
int y = (int) event.getRawY();
// + insideScrollView.getScrollY();
mParams.leftMargin = x - mImgWidth / 2 - location[0];
if (x <= 0) {
mParams.leftMargin = mImgWidth;
} else if (x > (getMeasuredWidth() - mImgWidth)) {
mParams.leftMargin = getMeasuredWidth() - mImgWidth;
}
// TODO Must calculate all padding control
mParams.topMargin = (int) (y - (location[1] + mImgHeight * 1.5f));
if (mParams.topMargin <= 1) {
mParams.topMargin = 1;
}
v.setLayoutParams(mParams);
updateSelectionByMovementImgControls(mParams.leftMargin,
mParams.topMargin);
break;
case MotionEvent.ACTION_UP:
if (selectableTextViewerListener != null) {
selectableTextViewerListener.endSelectingText(
SelectableTextViewer.this, getSelectedText());
}
break;
default:
disallowIntercept(false);
break;
}
return true;
}
};
this.imgEndSelect.setOnTouchListener(onTouchSelectionControl);
this.imgStartSelect.setOnTouchListener(onTouchSelectionControl);
this.imgEndSelect.setVisibility(View.GONE);
this.imgStartSelect.setVisibility(View.GONE);
}
public void updateSelectionByMovementImgControls(int x, int y) {
if (mCurrentControlFocused.equals(imgStartSelect)) {
this.mStartSelect = getOffsetByCoordinates(x + mImgWidth / 2, y);
} else if (mCurrentControlFocused.equals(imgEndSelect)) {
this.mEndSelect = getOffsetByCoordinates(x + mImgWidth / 2, y);
}
updateSelectionSpan();
}
protected Layout updateSelectionSpan() {
Layout retLayout = this.textView.getLayout();
if (this.mStartSelect > -1 && this.mEndSelect > -1) {
if (this.mStartSelect > this.mEndSelect) {
int temp = mEndSelect;
this.mEndSelect = mStartSelect;
this.mStartSelect = temp;
showSelectionControls();
}
SpannedString spannable = (SpannedString) this.textView.getText();
SpannableStringBuilder ssb = new SpannableStringBuilder(spannable);
ssb.removeSpan(this.spanBackgroundColored);
ssb.setSpan(this.spanBackgroundColored, this.mStartSelect,
this.mEndSelect, Spannable.SPAN_USER);
this.textView.setText(ssb);
this.textView.requestLayout();
if (this.selectableTextViewerListener != null) {
this.selectableTextViewerListener.updateSelection(this);
}
}
return retLayout;
}
protected void showSelectionControls() {
if (this.mStartSelect > -1 && this.mEndSelect > -1) {
Layout layout = updateSelectionSpan();
Rect parentTextViewRect = new Rect();
LayoutParams startLP = (LayoutParams) this.imgStartSelect
.getLayoutParams();
float xStart = layout.getPrimaryHorizontal(this.mStartSelect)
- mImgWidth / 2;
float yStart = layout.getLineBounds(
layout.getLineForOffset(this.mStartSelect),
parentTextViewRect);
startLP.setMargins((int) xStart, (int) yStart, -1, -1);
this.imgStartSelect.setLayoutParams(startLP);
this.imgStartSelect.setVisibility(View.VISIBLE);
LayoutParams endLP = (LayoutParams) this.imgEndSelect
.getLayoutParams();
float xEnd = layout.getPrimaryHorizontal(this.mEndSelect)
- mImgWidth / 2;
float yEnd = layout.getLineBounds(
layout.getLineForOffset(this.mEndSelect),
parentTextViewRect);
endLP.setMargins((int) xEnd, (int) yEnd, -1, -1);
this.imgEndSelect.setLayoutParams(endLP);
this.imgEndSelect.setVisibility(View.VISIBLE);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (this.imgStartSelect != null) {
if (this.imgStartSelect.getVisibility() == View.GONE) {
this.onTouchDownCalcSelections(event);
disallowIntercept(false);
} else {
this.stopSelecting();
}
}
} else {
this.disallowIntercept(false);
}
return super.onTouchEvent(event);
}
private void hideSelectionControls() {
this.imgStartSelect.setVisibility(View.GONE);
this.imgEndSelect.setVisibility(View.GONE);
}
private int getOffsetByCoordinates(int x, int y) {
int retOffset = -1;
Layout layout = this.textView.getLayout();
if (layout != null) {
int line = layout.getLineForVertical(y);
retOffset = layout.getOffsetForHorizontal(line, x);
}
return retOffset;
}
private void onTouchDownCalcSelections(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
this.mStartSelect = getOffsetByCoordinates(x, y);
if (this.mStartSelect > -1) {
// Calculate text end
String tempStr = this.textView.getText().toString();
tempStr = tempStr.substring(this.mStartSelect);
Pattern pt = Pattern.compile("\\s");
Matcher mt = pt.matcher(tempStr);
if (mt.find()) {
String match = mt.group(0);
tempStr = tempStr.substring(0, tempStr.indexOf(match));
}
this.mEndSelect = this.mStartSelect + tempStr.length();
}
}
public void setText(SpannableStringBuilder builder) {
this.textView.setText(builder);
}
public ImageView getImgEndSelect() {
return imgEndSelect;
}
public ImageView getImgStartSelect() {
return imgStartSelect;
}
/**
* For this all doing
*
* #return
*/
public String getSelectedText() {
String retSelectedString = null;
if (this.mStartSelect > -1 && this.mEndSelect > -1) {
retSelectedString = this.textView.getText()
.subSequence(this.mStartSelect, this.mEndSelect).toString();
}
return retSelectedString;
}
/**
* Hides cursors and clears
*
* #return
*/
public void stopSelecting() {
this.hideSelectionControls();
SpannedString spannable = (SpannedString) this.textView.getText();
SpannableStringBuilder ssb = new SpannableStringBuilder(spannable);
ssb.removeSpan(this.spanBackgroundColored);
this.setText(ssb);
if (selectableTextViewerListener != null) {
selectableTextViewerListener.stopSelectingText(
SelectableTextViewer.this, getSelectedText());
}
}
}
you have to this method as re-use, customize this method as per your use. this is just a concept.
// text comes from textview.gettext or database text and invalidate the view.
protected Layout updateSelectionSpan(Strint text) {
Layout retLayout = this.textView.getLayout();
if (this.mStartSelect > -1 && this.mEndSelect > -1) {
if (this.mStartSelect > this.mEndSelect) {
int temp = mEndSelect;
this.mEndSelect = mStartSelect;
this.mStartSelect = temp;
showSelectionControls();
}
SpannedString spannable = (SpannedString) text;
SpannableStringBuilder ssb = new SpannableStringBuilder(spannable);
ssb.removeSpan(this.spanBackgroundColored);
ssb.setSpan(this.spanBackgroundColored, this.mStartSelect,
this.mEndSelect, Spannable.SPAN_USER);
this.textView.setText(ssb);
this.textView.requestLayout();
if (this.selectableTextViewerListener != null) {
this.selectableTextViewerListener.updateSelection(this);
}
}
return retLayout;
}
I want make fold animation in both horizontal & vertical and i followed the below link for (DevBytes) for making folding animation.However this works for only for single image. How to make it to work for multiple Image Folding one by one (By swiping and autoplay)
Folding Layout class:
public class FoldingLayout extends ViewGroup {
public static enum Orientation {
VERTICAL,
HORIZONTAL
}
private final String FOLDING_VIEW_EXCEPTION_MESSAGE = "Folding Layout can only 1 child at " +
"most";
private final float SHADING_ALPHA = 0.8f;
private final float SHADING_FACTOR = 0.5f;
private final int DEPTH_CONSTANT = 1500;
private final int NUM_OF_POLY_POINTS = 8;
private Rect[] mFoldRectArray;
private Matrix [] mMatrix;
private Orientation mOrientation = Orientation.HORIZONTAL;
private float mAnchorFactor = 0;
private float mFoldFactor = 0;
private int mNumberOfFolds = 2;
private boolean mIsHorizontal = true;
private int mOriginalWidth = 0;
private int mOriginalHeight = 0;
private float mFoldMaxWidth = 0;
private float mFoldMaxHeight = 0;
private float mFoldDrawWidth = 0;
private float mFoldDrawHeight = 0;
private boolean mIsFoldPrepared = false;
private boolean mShouldDraw = true;
private Paint mSolidShadow;
private Paint mGradientShadow;
private LinearGradient mShadowLinearGradient;
private Matrix mShadowGradientMatrix;
private float [] mSrc;
private float [] mDst;
private OnFoldListener mFoldListener;
private float mPreviousFoldFactor = 0;
private Bitmap mFullBitmap;
private Rect mDstRect;
public FoldingLayout(Context context) {
super(context);
}
public FoldingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FoldingLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected boolean addViewInLayout(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
throwCustomException(getChildCount());
boolean returnValue = super.addViewInLayout(child, index, params, preventRequestLayout);
return returnValue;
}
#Override
public void addView(View child, int index, LayoutParams params) {
throwCustomException(getChildCount());
super.addView(child, index, params);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
View child = getChildAt(0);
measureChild(child,widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
View child = getChildAt(0);
child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
updateFold();
}
private class NumberOfFoldingLayoutChildrenException extends RuntimeException {
public NumberOfFoldingLayoutChildrenException(String message) {
super(message);
}
}
private void throwCustomException (int numOfChildViews) {
if (numOfChildViews == 1) {
throw new NumberOfFoldingLayoutChildrenException(FOLDING_VIEW_EXCEPTION_MESSAGE);
}
}
public void setFoldListener(OnFoldListener foldListener) {
mFoldListener = foldListener;
}
public void setFoldFactor(float foldFactor) {
if (foldFactor != mFoldFactor) {
mFoldFactor = foldFactor;
calculateMatrices();
invalidate();
}
}
public void setOrientation(Orientation orientation) {
if (orientation != mOrientation) {
mOrientation = orientation;
updateFold();
}
}
public void setAnchorFactor(float anchorFactor) {
if (anchorFactor != mAnchorFactor) {
mAnchorFactor = anchorFactor;
updateFold();
}
}
public void setNumberOfFolds(int numberOfFolds) {
if (numberOfFolds != mNumberOfFolds) {
mNumberOfFolds = numberOfFolds;
updateFold();
}
}
public float getAnchorFactor() {
return mAnchorFactor;
}
public Orientation getOrientation() {
return mOrientation;
}
public float getFoldFactor() {
return mFoldFactor;
}
public int getNumberOfFolds() {
return mNumberOfFolds;
}
private void updateFold() {
prepareFold(mOrientation, mAnchorFactor, mNumberOfFolds);
calculateMatrices();
invalidate();
}
private void prepareFold(Orientation orientation, float anchorFactor, int numberOfFolds) {
mSrc = new float[NUM_OF_POLY_POINTS];
mDst = new float[NUM_OF_POLY_POINTS];
mDstRect = new Rect();
mFoldFactor = 0;
mPreviousFoldFactor = 0;
mIsFoldPrepared = false;
mSolidShadow = new Paint();
mGradientShadow = new Paint();
mOrientation = orientation;
mIsHorizontal = (orientation == Orientation.HORIZONTAL);
if (mIsHorizontal) {
mShadowLinearGradient = new LinearGradient(0, 0, SHADING_FACTOR, 0, Color.BLACK,
Color.TRANSPARENT, TileMode.CLAMP);
} else {
mShadowLinearGradient = new LinearGradient(0, 0, 0, SHADING_FACTOR, Color.BLACK,
Color.TRANSPARENT, TileMode.CLAMP);
}
mGradientShadow.setStyle(Style.FILL);
mGradientShadow.setShader(mShadowLinearGradient);
mShadowGradientMatrix = new Matrix();
mAnchorFactor = anchorFactor;
mNumberOfFolds = numberOfFolds;
mOriginalWidth = getMeasuredWidth();
mOriginalHeight = getMeasuredHeight();
mFoldRectArray = new Rect[mNumberOfFolds];
mMatrix = new Matrix [mNumberOfFolds];
for (int x = 0; x < mNumberOfFolds; x++) {
mMatrix[x] = new Matrix();
}
int h = mOriginalHeight;
int w = mOriginalWidth;
if (FoldingLayoutActivity.IS_JBMR2) {
mFullBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mFullBitmap);
getChildAt(0).draw(canvas);
}
int delta = Math.round(mIsHorizontal ? ((float) w) / ((float) mNumberOfFolds) :
((float) h) /((float) mNumberOfFolds));
for (int x = 0; x < mNumberOfFolds; x++) {
if (mIsHorizontal) {
int deltap = (x + 1) * delta > w ? w - x * delta : delta;
mFoldRectArray[x] = new Rect(x * delta, 0, x * delta + deltap, h);
} else {
int deltap = (x + 1) * delta > h ? h - x * delta : delta;
mFoldRectArray[x] = new Rect(0, x * delta, w, x * delta + deltap);
}
}
if (mIsHorizontal) {
mFoldMaxHeight = h;
mFoldMaxWidth = delta;
} else {
mFoldMaxHeight = delta;
mFoldMaxWidth = w;
}
mIsFoldPrepared = true;
}
private void calculateMatrices() {
mShouldDraw = true;
if (!mIsFoldPrepared) {
return;
}
if (mFoldFactor == 1) {
mShouldDraw = false;
return;
}
if (mFoldFactor == 0 && mPreviousFoldFactor > 0) {
mFoldListener.onEndFold();
}
if (mPreviousFoldFactor == 0 && mFoldFactor > 0) {
mFoldListener.onStartFold();
}
mPreviousFoldFactor = mFoldFactor;
for (int x = 0; x < mNumberOfFolds; x++) {
mMatrix[x].reset();
}
float cTranslationFactor = 1 - mFoldFactor;
float translatedDistance = mIsHorizontal ? mOriginalWidth * cTranslationFactor :
mOriginalHeight * cTranslationFactor;
float translatedDistancePerFold = Math.round(translatedDistance / mNumberOfFolds);
mFoldDrawWidth = mFoldMaxWidth < translatedDistancePerFold ?
translatedDistancePerFold : mFoldMaxWidth;
mFoldDrawHeight = mFoldMaxHeight < translatedDistancePerFold ?
translatedDistancePerFold : mFoldMaxHeight;
float translatedDistanceFoldSquared = translatedDistancePerFold * translatedDistancePerFold;
float depth = mIsHorizontal ?
(float)Math.sqrt((double)(mFoldDrawWidth * mFoldDrawWidth -
translatedDistanceFoldSquared)) :
(float)Math.sqrt((double)(mFoldDrawHeight * mFoldDrawHeight -
translatedDistanceFoldSquared));
float scaleFactor = DEPTH_CONSTANT / (DEPTH_CONSTANT + depth);
float scaledWidth, scaledHeight, bottomScaledPoint, topScaledPoint, rightScaledPoint,
leftScaledPoint;
if (mIsHorizontal) {
scaledWidth = mFoldDrawWidth * cTranslationFactor;
scaledHeight = mFoldDrawHeight * scaleFactor;
} else {
scaledWidth = mFoldDrawWidth * scaleFactor;
scaledHeight = mFoldDrawHeight * cTranslationFactor;
}
topScaledPoint = (mFoldDrawHeight - scaledHeight) / 2.0f;
bottomScaledPoint = topScaledPoint + scaledHeight;
leftScaledPoint = (mFoldDrawWidth - scaledWidth) / 2.0f;
rightScaledPoint = leftScaledPoint + scaledWidth;
float anchorPoint = mIsHorizontal ? mAnchorFactor * mOriginalWidth :
mAnchorFactor * mOriginalHeight;
/* The fold along which the anchor point is located. */
float midFold = mIsHorizontal ? (anchorPoint / mFoldDrawWidth) : anchorPoint /
mFoldDrawHeight;
mSrc[0] = 0;
mSrc[1] = 0;
mSrc[2] = 0;
mSrc[3] = mFoldDrawHeight;
mSrc[4] = mFoldDrawWidth;
mSrc[5] = 0;
mSrc[6] = mFoldDrawWidth;
mSrc[7] = mFoldDrawHeight;
for (int x = 0; x < mNumberOfFolds; x++) {
boolean isEven = (x % 2 == 0);
if (mIsHorizontal) {
mDst[0] = (anchorPoint > x * mFoldDrawWidth) ? anchorPoint + (x - midFold) *
scaledWidth : anchorPoint - (midFold - x) * scaledWidth;
mDst[1] = isEven ? 0 : topScaledPoint;
mDst[2] = mDst[0];
mDst[3] = isEven ? mFoldDrawHeight: bottomScaledPoint;
mDst[4] = (anchorPoint > (x + 1) * mFoldDrawWidth) ? anchorPoint + (x + 1 - midFold)
* scaledWidth : anchorPoint - (midFold - x - 1) * scaledWidth;
mDst[5] = isEven ? topScaledPoint : 0;
mDst[6] = mDst[4];
mDst[7] = isEven ? bottomScaledPoint : mFoldDrawHeight;
} else {
mDst[0] = isEven ? 0 : leftScaledPoint;
mDst[1] = (anchorPoint > x * mFoldDrawHeight) ? anchorPoint + (x - midFold) *
scaledHeight : anchorPoint - (midFold - x) * scaledHeight;
mDst[2] = isEven ? leftScaledPoint: 0;
mDst[3] = (anchorPoint > (x + 1) * mFoldDrawHeight) ? anchorPoint + (x + 1 -
midFold) * scaledHeight : anchorPoint - (midFold - x - 1) * scaledHeight;
mDst[4] = isEven ? mFoldDrawWidth : rightScaledPoint;
mDst[5] = mDst[1];
mDst[6] = isEven ? rightScaledPoint : mFoldDrawWidth;
mDst[7] = mDst[3];
}
for (int y = 0; y < 8; y ++) {
mDst[y] = Math.round(mDst[y]);
}
int alpha = (int) (mFoldFactor * 255 * SHADING_ALPHA);
mSolidShadow.setColor(Color.argb(alpha, 0, 0, 0));
if (mIsHorizontal) {
mShadowGradientMatrix.setScale(mFoldDrawWidth, 1);
mShadowLinearGradient.setLocalMatrix(mShadowGradientMatrix);
} else {
mShadowGradientMatrix.setScale(1, mFoldDrawHeight);
mShadowLinearGradient.setLocalMatrix(mShadowGradientMatrix);
}
mGradientShadow.setShader(mShadowLinearGradient);
mGradientShadow.setAlpha(alpha);
}
#Override
protected void dispatchDraw(Canvas canvas) {
if (!mIsFoldPrepared || mFoldFactor == 0) {
super.dispatchDraw(canvas);
return;
}
if (!mShouldDraw) {
return;
}
for (int x = 0; x < mNumberOfFolds; x++) {
src = mFoldRectArray[x];
canvas.concat(mMatrix[x]);
if (FoldingLayoutActivity.IS_JBMR2) {
mDstRect.set(0, 0, src.width(), src.height());
canvas.drawBitmap(mFullBitmap, src, mDstRect, null);
} else {
canvas.clipRect(0, 0, src.right - src.left, src.bottom - src.top);
if (mIsHorizontal) {
canvas.translate(-src.left, 0);
} else {
canvas.translate(0, -src.top);
}
super.dispatchDraw(canvas);
if (mIsHorizontal) {
canvas.translate(src.left, 0);
} else {
canvas.translate(0, src.top);
}
}
if (x % 2 == 0) {
canvas.drawRect(0, 0, mFoldDrawWidth, mFoldDrawHeight, mSolidShadow);
} else {
canvas.drawRect(0, 0, mFoldDrawWidth, mFoldDrawHeight, mGradientShadow);
}
canvas.restore();
}
}
}
// onFoldListener
public interface OnFoldListener {
public void onStartFold();
public void onEndFold();
}
// FoldingLayoutActivity
public class FoldingLayoutActivity extends Activity {
private final int ANTIALIAS_PADDING = 1;
private final int FOLD_ANIMATION_DURATION = 1000;
static final boolean IS_JBMR2 = Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR2;
private FoldingLayout mFoldLayout;
private SeekBar mAnchorSeekBar;
private Orientation mOrientation = Orientation.HORIZONTAL;
private int mTranslation = 0;
private int mNumberOfFolds = 2;
private int mParentPositionY = -1;
private int mTouchSlop = -1;
private float mAnchorFactor = 0;
private boolean mDidLoadSpinner = true;
private boolean mDidNotStartScroll = true;
private boolean mIsCameraFeed = false;
private boolean mIsSepiaOn = true;
private GestureDetector mScrollGestureDetector;
private ItemSelectedListener mItemSelectedListener;
private Camera mCamera;
private TextureView mTextureView;
private ImageView mImageView;
private Paint mSepiaPaint;
private Paint mDefaultPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fold);
mImageView = (ImageView)findViewById(R.id.image_view);
mImageView.setPadding(ANTIALIAS_PADDING, ANTIALIAS_PADDING, ANTIALIAS_PADDING,
ANTIALIAS_PADDING);
mImageView.setScaleType(ImageView.ScaleType.FIT_XY);
mImageView.setImageDrawable(getResources().getDrawable(R.drawable.image));
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
mAnchorSeekBar = (SeekBar)findViewById(R.id.anchor_seek_bar);
mFoldLayout = (FoldingLayout)findViewById(R.id.fold_view);
mFoldLayout.setBackgroundColor(Color.BLACK);
mFoldLayout.setFoldListener(mOnFoldListener);
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
mAnchorSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);
mScrollGestureDetector = new GestureDetector(this, new ScrollGestureDetector());
mItemSelectedListener = new ItemSelectedListener();
mDefaultPaint = new Paint();
mSepiaPaint = new Paint();
ColorMatrix m1 = new ColorMatrix();
ColorMatrix m2 = new ColorMatrix();
m1.setSaturation(0);
m2.setScale(1f, .95f, .82f, 1.0f);
m1.setConcat(m2, m1);
mSepiaPaint.setColorFilter(new ColorMatrixColorFilter(m1));
}
private OnFoldListener mOnFoldListener =
new OnFoldListener() {
#Override
public void onStartFold() {
if (mIsSepiaOn) {
setSepiaLayer(mFoldLayout.getChildAt(0), true);
}
}
#Override
public void onEndFold() {
setSepiaLayer(mFoldLayout.getChildAt(0), false);
}
};
private void setSepiaLayer (View view, boolean isSepiaLayerOn) {
if (!IS_JBMR2) {
if (isSepiaLayerOn) {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
view.setLayerPaint(mSepiaPaint);
} else {
view.setLayerPaint(mDefaultPaint);
}
}
}
private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView
.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
mCamera = Camera.open();
if (mCamera == null && Camera.getNumberOfCameras() > 1) {
mCamera = mCamera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
}
if (mCamera == null) {
return;
}
try {
mCamera.setPreviewTexture(surfaceTexture);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar
.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
mTranslation = 0;
mAnchorFactor = ((float)mAnchorSeekBar.getProgress())/100.0f;
mFoldLayout.setAnchorFactor(mAnchorFactor);
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (IS_JBMR2) {
getMenuInflater().inflate(R.menu.fold_with_bug, menu);
} else {
getMenuInflater().inflate(R.menu.fold, menu);
}
Spinner s = (Spinner) menu.findItem(R.id.num_of_folds).getActionView();
s.setOnItemSelectedListener(mItemSelectedListener);
return true;
}
#Override
public void onWindowFocusChanged (boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
int[] loc = new int[2];
mFoldLayout.getLocationOnScreen(loc);
mParentPositionY = loc[1];
}
#Override
public boolean onTouchEvent(MotionEvent me) {
return mScrollGestureDetector.onTouchEvent(me);
}
#Override
public boolean onOptionsItemSelected (MenuItem item) {
switch(item.getItemId()) {
case R.id.animate_fold:
animateFold();
break;
case R.id.toggle_orientation:
mOrientation = (mOrientation == Orientation.HORIZONTAL) ? Orientation.VERTICAL :
Orientation.HORIZONTAL;
item.setTitle((mOrientation == Orientation.HORIZONTAL) ? R.string.vertical :
R.string.horizontal);
mTranslation = 0;
mFoldLayout.setOrientation(mOrientation);
break;
case R.id.camera_feed:
mIsCameraFeed = !mIsCameraFeed;
item.setTitle(mIsCameraFeed ? R.string.static_image : R.string.camera_feed);
item.setChecked(mIsCameraFeed);
if (mIsCameraFeed) {
mFoldLayout.removeView(mImageView);
mFoldLayout.addView(mTextureView, new ViewGroup.LayoutParams(
mFoldLayout.getWidth(), mFoldLayout.getHeight()));
} else {
mFoldLayout.removeView(mTextureView);
mFoldLayout.addView(mImageView, new ViewGroup.LayoutParams(
mFoldLayout.getWidth(), mFoldLayout.getHeight()));
}
mTranslation = 0;
break;
case R.id.sepia:
mIsSepiaOn = !mIsSepiaOn;
item.setChecked(!mIsSepiaOn);
if (mIsSepiaOn && mFoldLayout.getFoldFactor() != 0) {
setSepiaLayer(mFoldLayout.getChildAt(0), true);
} else {
setSepiaLayer(mFoldLayout.getChildAt(0), false);
}
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
public void animateFold ()
{
float foldFactor = mFoldLayout.getFoldFactor();
ObjectAnimator animator = ObjectAnimator.ofFloat(mFoldLayout, "foldFactor", foldFactor, 1);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.setRepeatCount(1);
animator.setDuration(FOLD_ANIMATION_DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
private class ItemSelectedListener implements OnItemSelectedListener {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
mNumberOfFolds = Integer.parseInt(parent.getItemAtPosition(pos).toString());
if (mDidLoadSpinner) {
mDidLoadSpinner = false;
} else {
mTranslation = 0;
mFoldLayout.setNumberOfFolds(mNumberOfFolds);
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
}
private class ScrollGestureDetector extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onDown (MotionEvent e) {
mDidNotStartScroll = true;
return true;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
int touchSlop = 0;
float factor;
if (mOrientation == Orientation.VERTICAL) {
factor = Math.abs((float)(mTranslation) / (float)(mFoldLayout.getHeight()));
if (e2.getY() - mParentPositionY <= mFoldLayout.getHeight()
&& e2.getY() - mParentPositionY >= 0) {
if ((e2.getY() - mParentPositionY) > mFoldLayout.getHeight() * mAnchorFactor) {
mTranslation -= (int)distanceY;
touchSlop = distanceY < 0 ? -mTouchSlop : mTouchSlop;
} else {
mTranslation += (int)distanceY;
touchSlop = distanceY < 0 ? mTouchSlop : -mTouchSlop;
}
mTranslation = mDidNotStartScroll ? mTranslation + touchSlop : mTranslation;
if (mTranslation < -mFoldLayout.getHeight()) {
mTranslation = -mFoldLayout.getHeight();
}
}
} else {
factor = Math.abs(((float)mTranslation) / ((float) mFoldLayout.getWidth()));
if (e2.getRawX() > mFoldLayout.getWidth() * mAnchorFactor) {
mTranslation -= (int)distanceX;
touchSlop = distanceX < 0 ? -mTouchSlop : mTouchSlop;
} else {
mTranslation += (int)distanceX;
touchSlop = distanceX < 0 ? mTouchSlop : -mTouchSlop;
}
mTranslation = mDidNotStartScroll ? mTranslation + touchSlop : mTranslation;
if (mTranslation < -mFoldLayout.getWidth()) {
mTranslation = -mFoldLayout.getWidth();
}
}
mDidNotStartScroll = false;
if (mTranslation > 0) {
mTranslation = 0;
}
mFoldLayout.setFoldFactor(factor);
return true;
}
}
}
//activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.android.foldinglayout.FoldingLayout
android:layout_weight="1"
android:id="#+id/fold_view"
android:layout_width="match_parent"
android:layout_height="0dp">
<ImageView
android:id="#+id/image_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="fitXY"/>
</com.example.android.foldinglayout.FoldingLayout>
<SeekBar
android:id="#+id/anchor_seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"/>
</LinearLayout>
Here is my source code.
/*
* This code is a modification of the Android LunarLander example.
*/
package net.simplifiedcoding.detectoutgoingcalls.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.RotateAnimation;
import net.simplifiedcoding.detectoutgoingcalls.R;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* View that draws, takes keystrokes, etc. for a simple LunarLander game.
* <p/>
* Has a mode which RUNNING, PAUSED, etc. draw() renders the
* ship, and does an invalidate() to prompt another draw() as soon as possible
* by the system.
*/
public class RotaryDialerView extends View {
private float rotorAngle = 0F;
private final Drawable rotorDrawable;
private final int r1 = 50;
private final int r2 = 160;
private double lastFi;
private int startN;
public MediaPlayer mPlayer;
private int width;
private int height;
private boolean soundRotating;
android.media.MediaPlayer.OnCompletionListener soundListener;
private boolean playSound;
MainActivity activity = new MainActivity();
public RotaryDialerView(Context context) {
this(context, null);
soundListener = new android.media.MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaplayer) {
stop();
}
};
}
public RotaryDialerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RotaryDialerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
playSound = false;
startN = -1;
soundRotating = false;
rotorDrawable = context.getResources().getDrawable(R.drawable.dialer);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int availableWidth = getRight() - getLeft();
int availableHeight = getBottom() - getTop();
int x = availableWidth / 2;
int y = availableHeight / 2;
canvas.save();
rotorDrawable.setBounds(0, 0, rotorDrawable.getIntrinsicWidth(),
rotorDrawable.getIntrinsicHeight());
if (rotorAngle != 0) {
canvas.rotate(rotorAngle, x, y);
}
rotorDrawable.draw(canvas);
canvas.restore();
}
protected void onMeasure(int i, int j) {
height = android.view.View.MeasureSpec.getSize(j);
width = android.view.View.MeasureSpec.getSize(i);
setMeasuredDimension(width, height);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
final float x0 = width / 2;
final float y0 = height / 2;
float x1 = event.getX();
float y1 = event.getY();
float x = x0 - x1;
float y = y0 - y1;
double r = Math.sqrt(x * x + y * y);
double sinfi = y / r;
double fi = Math.toDegrees(Math.asin(sinfi));
if (x1 > x0 && y0 > y1) {
fi = 180D - fi;
} else if (x1 > x0 && y1 > y0) {
fi = 180D - fi;
} else if (x0 > x1 && y1 > y0) {
fi += 360D;
}
boolean isComplete = false;
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
Log.e("MotionEvent.ACTION_MOVE", "" + MotionEvent.ACTION_MOVE);
if (r > r1 && r < r2) {
if (!soundRotating) {
soundRotating = true;
playSound(startN);
}
final float angle2 = rotorAngle % 360;
int number2 = Math.round(angle2 - 20) / 30;
rotorAngle += Math.abs(fi - lastFi) + 0.25f;
rotorAngle %= 360F;
lastFi = fi;
if (startN >= 10 && !isComplete) {
isComplete = true;
}
// if (number2 < startN || startN == 0 && !isComplete) {
invalidate();
//}
return false;
}
case MotionEvent.ACTION_DOWN:
// playMusic();
// mPlayer2.pause();
calculateStartN(rotorAngle);
rotorAngle = 0F;
lastFi = fi;
return true;
// }
//return false;
case MotionEvent.ACTION_UP:
//mPlayer2.pause();
soundRotating = false;
final float angle = rotorAngle % 360;
int number = Math.round(angle - 20) / 30;
playSound_2(number);
final float fl22 = Math.round(angle - 20) - number * 30;
Log.e("angle", "" + fl22);
if (number > 0) {
if (number == 10) {
number = 0;
}
// if (fl2 < 8.0 && fl2 > 4.0) {
fireDialListenerEvent(number);
//return true;
//}
}
rotorAngle = 0F;
post(new Runnable() {
public void run() {
float fromDegrees = angle;
Animation anim = new RotateAnimation(fromDegrees, 0, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5F);
anim.setInterpolator(AnimationUtils.loadInterpolator(getContext(), android.R.anim.decelerate_interpolator));
anim.setAnimationListener(animListener);
anim.setDuration((long) (angle * 5F));
startAnimation(anim);
// playSound();
// angle = 00;//x0;
}
});
startN = -1;
isComplete = false;
return true;
default:
break;
}
return super.onTouchEvent(event);
}
public interface DialListener {
void onDial(int number);
}
private final List<DialListener> dialListeners = new ArrayList<DialListener>();
public void addDialListener(DialListener listener) {
dialListeners.add(listener);
}
public void removeDialListener(DialListener listener) {
dialListeners.remove(listener);
}
private void fireDialListenerEvent(int number) {
for (DialListener listener : dialListeners) {
listener.onDial(number);
Log.e("position ", "Reached");
}
}
private android.view.animation.Animation.AnimationListener animListener = new android.view.animation.Animation.AnimationListener() {
public void onAnimationEnd(Animation animation) {
activity.stopVibrate();
}
public void onAnimationRepeat(Animation animation) {
}
public void onAnimationStart(Animation animation) {
}
};
public void playSound(int n) {
try {
Log.e("n value is", "" + n);
boolean mStartPlaying = true;
if (mStartPlaying == true) {
mPlayer = new MediaPlayer();
Uri uri = Uri.parse("android.resource://net.simplifiedcoding.detectoutgoingcalls/" + activity.SOUNDS_R[n]);
mPlayer.setOnCompletionListener(soundListener);
mPlayer.setDataSource(getContext(), uri);
mPlayer.prepare();
mPlayer.setLooping(false);
mPlayer.start();
} else {
// stopPlaying();
//rePlay.setText("Replay");
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
mStartPlaying = !mStartPlaying;
} catch (IOException e) {
Log.e("ERR", "prepare() failed");
}
}
public void playSound_2(int n) {
try {
boolean mStartPlaying = true;
if (mStartPlaying == true) {
mPlayer = new MediaPlayer();
Uri uri = Uri.parse("android.resource://net.simplifiedcoding.detectoutgoingcalls/" + activity.SOUNDS_S[n]);
mPlayer.setOnCompletionListener(soundListener);
mPlayer.setDataSource(getContext(), uri);
mPlayer.prepare();
mPlayer.setLooping(false);
mPlayer.start();
} else {
// stopPlaying();
//rePlay.setText("Replay");
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
mStartPlaying = !mStartPlaying;
} catch (IOException e) {
Log.e("ERR", "prepare() failed");
}
}
public void stop() {
try {
mPlayer.release();
mPlayer.stop();
return;
}
// Misplaced declaration of an exception variable
catch (Exception mediaplayer) {
return;
}
}
private void calculateStartN(double d) {
if (d >= 0.0D && d < 30D) {
startN = 5;
} else {
if (d >= 30D && d < 60D) {
startN = 4;
return;
}
if (d >= 60D && d < 90D) {
startN = 3;
return;
}
if (d >= 90D && d < 120D) {
startN = 2;
return;
}
if (d >= 120D && d <= 150D) {
startN = 1;
return;
}
if (d >= 210D && d < 240D) {
startN = 0;
return;
}
if (d >= 240D && d < 270D) {
startN = 9;
return;
}
if (d >= 270D && d < 300D) {
startN = 8;
return;
}
if (d >= 300D && d < 330D) {
startN = 7;
return;
}
if (d >= 330D && d <= 360D) {
startN = 6;
return;
}
}
}
}
The problem is when i rotate the dialer number it is not stooped when it reach the point.it rotate contentiously with out end.
here is the sample source code
http://www.ssaurel.com/blog/how-to-create-a-rotary-dialer-application-for-android/
every thing is perfect but the only issue is rotation is not stoped when it reach the end
Em...the title is not clearly, here is my question: i custom a view to display calendar, my logic is when user swipe horizontal it can switch month of current year, when user swipe vertical it can switch year of current month, like image below:
Here is my all code below and i delete some useless code:
public class MonthView extends View {
private static final Region[][] MONTH_REGIONS = new Region[6][7];
private DPCManager mCManager = DPCManager.getInstance();
private DPTManager mTManager = DPTManager.getInstance();
private TextPaint mTextPaint;
private Paint mPaint;
private Scroller mScroller;
private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();
private AccelerateInterpolator accelerateInterpolator = new AccelerateInterpolator();
private OnDateChangeListener onDateChangeListener;
private ScaleAnimationListener scaleAnimationListener = new ScaleAnimationListener();
private DPMode mode;
private int indexYear, indexMonth;
private int centerYear, centerMonth;
private int leftYear, leftMonth;
private int rightYear, rightMonth;
private int topYear, topMonth;
private int bottomYear, bottomMonth;
private int width, height;
private int lastHeight, nextHeight;
private int baseSize;
private int sizeDecor, sizeDecor2x, sizeDecor3x;
private int lastPointX, lastPointY;
private int lastMoveX, lastMoveY;
private int criticalWidth, criticalHeight;
private float sizeTextGregorian, sizeTextFestival;
private float offsetYFestival1, offsetYFestival2;
private boolean isSlideV;
private Map<String, BGCircle> circlesAppear = new HashMap<>();
private Map<String, BGCircle> circlesDisappear = new HashMap<>();
private List<String> dateSelected = new ArrayList<>();
public interface OnDateChangeListener {
void onMonthChange(int month);
void onYearChange(int year);
}
public MonthView(Context context) {
this(context, null);
}
public MonthView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
mTextPaint = new TextPaint();
mTextPaint.setTextAlign(Paint.Align.CENTER);
mPaint = new Paint();
}
void setOnDateChangeListener(OnDateChangeListener onDateChangeListener) {
this.onDateChangeListener = onDateChangeListener;
}
void setMode(DPMode mode) {
this.mode = mode;
}
void setDate(int year, int month) {
centerYear = year;
centerMonth = month;
indexYear = 0;
indexMonth = 0;
computeDate();
requestLayout();
invalidate();
}
private void computeDate() {
rightYear = leftYear = centerYear;
topYear = centerYear - 1;
bottomYear = centerYear + 1;
topMonth = centerMonth;
bottomMonth = centerMonth;
rightMonth = centerMonth + 1;
leftMonth = centerMonth - 1;
if (centerMonth == 12) {
rightYear++;
rightMonth = 1;
}
if (centerMonth == 1) {
leftYear--;
leftMonth = 12;
}
if (null != onDateChangeListener) {
onDateChangeListener.onYearChange(centerYear);
onDateChangeListener.onMonthChange(centerMonth);
}
}
#Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
} else {
}
}
boolean isNewEvent = false;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isNewEvent = true;
lastPointX = (int) event.getX();
lastPointY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
if (isNewEvent) {
if (Math.abs(lastPointX - event.getX()) > 100) {
isSlideV = false;
isNewEvent = false;
} else if (Math.abs(lastPointY - event.getY()) > 50) {
isSlideV = true;
isNewEvent = false;
}
}
if (isSlideV) {
int totalMoveY = (int) (lastPointY - event.getY()) + lastMoveY;
smoothScrollTo(0, totalMoveY);
} else {
int totalMoveX = (int) (lastPointX - event.getX()) + lastMoveX;
smoothScrollTo(totalMoveX, 0);
}
break;
case MotionEvent.ACTION_UP:
if (isSlideV) {
if (Math.abs(lastPointY - event.getY()) > 25) {
if (lastPointY < event.getY()) {
if (Math.abs(lastPointY - event.getY()) >= criticalHeight) {
indexYear--;
centerYear = centerYear - 1;
computeDate();
}
smoothScrollTo(0, height * indexYear);
lastMoveY = height * indexYear;
} else if (lastPointY > event.getY()) {
if (Math.abs(lastPointY - event.getY()) >= criticalHeight) {
indexYear++;
centerYear = centerYear + 1;
computeDate();
}
smoothScrollTo(0, height * indexYear);
lastMoveY = height * indexYear;
}
} else {
}
} else {
if (Math.abs(lastPointX - event.getX()) > 25) {
if (lastPointX > event.getX()) {
if (Math.abs(lastPointX - event.getX()) >= criticalWidth) {
indexMonth++;
centerMonth = (centerMonth + 1) % 13;
if (centerMonth == 0) {
centerMonth = 1;
centerYear++;
}
computeDate();
}
smoothScrollTo(width * indexMonth, 0);
lastMoveX = width * indexMonth;
} else if (lastPointX < event.getX()) {
if (Math.abs(lastPointX - event.getX()) >= criticalWidth) {
indexMonth--;
centerMonth = (centerMonth - 1) % 12;
if (centerMonth == 0) {
centerMonth = 12;
centerYear--;
}
computeDate();
}
smoothScrollTo(width * indexMonth, 0);
lastMoveX = width * indexMonth;
}
} else {
}
}
break;
}
return true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(measureWidth, measureWidth * 6 / 7F);
}
#Override
protected void onSizeChanged(int w, int h, int oldW, int oldH) {
width = w;
height = h;
criticalWidth = (int) (1F / 5F * width);
criticalHeight = (int) (1F / 5F * height);
baseSize = w;
int sizeCell = (int) (baseSize / 7F);
sizeDecor = (int) (sizeCell / 3F);
sizeDecor2x = sizeDecor * 2;
sizeDecor3x = sizeDecor * 3;
sizeTextGregorian = baseSize / 20F;
mTextPaint.setTextSize(sizeTextGregorian);
float heightGregorian = mTextPaint.getFontMetrics().bottom - mTextPaint.getFontMetrics().top;
sizeTextFestival = baseSize / 40F;
mTextPaint.setTextSize(sizeTextFestival);
float heightFestival = mTextPaint.getFontMetrics().bottom - mTextPaint.getFontMetrics().top;
offsetYFestival1 = (((Math.abs(mTextPaint.ascent() + mTextPaint.descent())) / 2F) +
heightFestival / 2F + heightGregorian / 2F) / 2F;
offsetYFestival2 = offsetYFestival1 * 2F;
for (int i = 0; i < MONTH_REGIONS.length; i++) {
for (int j = 0; j < MONTH_REGIONS[i].length; j++) {
Region region = new Region();
region.set((j * sizeCell), (i * sizeCell), sizeCell + (j * sizeCell),
sizeCell + (i * sizeCell));
MONTH_REGIONS[i][j] = region;
}
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.LTGRAY);
draw(canvas, width * (indexMonth - 1), height * indexYear, leftYear, leftMonth);
draw(canvas, width * indexMonth, height * indexYear, centerYear, centerMonth);
draw(canvas, width * (indexMonth + 1), height * indexYear, rightYear, rightMonth);
draw(canvas, width * indexMonth, height * (indexYear - 1), topYear, topMonth);
draw(canvas, width * indexMonth, height * (indexYear + 1), bottomYear, bottomMonth);
}
private void draw(Canvas canvas, int x, int y, int year, int month) {
canvas.save();
canvas.translate(x, y);
DPInfo[][] info = mCManager.obtainDPInfo(year, month);
for (int i = 0; i < info.length; i++) {
for (int j = 0; j < info[i].length; j++) {
draw(canvas, MONTH_REGIONS[i][j].getBounds(), info[i][j]);
}
}
canvas.restore();
}
private void draw(Canvas canvas, Rect rect, DPInfo info) {
drawGregorian(canvas, rect, info.strG, info.isWeekend);
}
private void drawGregorian(Canvas canvas, Rect rect, String str, boolean isWeekend) {
mTextPaint.setTextSize(sizeTextGregorian);
if (isWeekend) {
mTextPaint.setColor(mTManager.colorWeekend());
} else {
mTextPaint.setColor(mTManager.colorG());
}
canvas.drawText(str, rect.centerX(), rect.centerY(), mTextPaint);
}
private void smoothScrollTo(int fx, int fy) {
int dx = fx - mScroller.getFinalX();
int dy = fy - mScroller.getFinalY();
smoothScrollBy(dx, dy);
}
private void smoothScrollBy(int dx, int dy) {
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, 500);
invalidate();
}
}
If i swipe vertical to switch year, for example 2015/7-->2016/7-->2017/7, it's run correctly, but now if i swipe horizontal to switch month, for example 2017/7-->2017/6, everything will not display:
That's mean only horizontal and vertical on current month can touch and display correctly, for example the default display month is 2015/7, when i swipe to 2016/7 or 2017/7, i can't get the correct display when i swipe to 2017/6 or 2017/8, only swipe back to 2015/7 to swipe correctly can get the correct display of 2015/6 and 2015/8.
This problem troubled me many days, the coordinates and data of months all correct, i don't know why it happen, hope and thanks for your answer.
I am using MUPDF Library and i added features for manual zoom in, zoom out , rating, setting brightness. Now i am doing with long press the highlighted text and i have to show the meaning from my database. I am trying to do with two things one is clipboard or emulateShiftHeld the below feature is for only android ICS and JellyBean. Can any body suggest on whether any one thing will work for this feature what i am trying. Because on Long Press i can't able to capture the text. Suggestions will be helpful.
This id my MUPDF Activity:
public void createUI(Bundle savedInstanceState) {
if (core == null)
return;
// Now create the UI.
// First create the document view making use of the ReaderView's internal
// gesture recognition
mDocView = new ReaderView(this) {
private boolean showButtonsDisabled;
public void onLongPress(MotionEvent e) {
selectAndCopyText();
//mDocView.getSelectedItem();
//SelectText(mDocView);
/*emulateShiftHeld(layout);
clipboard =
(ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
clipboard.setText(clipboard.getText().toString());
//layout.findAll(clipboard.getText().toString());
//ClipMan.setPrimaryClip(clipboard);
//String s = (String) clipboard.getText();
//System.out.println("fsfasd"+ s);
CharSequence pasteData="";
ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);
pasteData = item.getText();
System.out.println("fsf"+pasteData);*/
//ClipData data = ClipData.newPlainText("", "");
///System.out.println("sdf" + data);
//copyClipboard();
}
#SuppressWarnings("deprecation")
public void selectAndCopyText() {
try {
Method m = WebView.class.getMethod("emulateShiftHeld", Boolean.TYPE);
m.invoke(mDocView, false);
} catch (Exception e) {
e.printStackTrace();
// fallback
KeyEvent shiftPressEvent = new KeyEvent(0,0,
KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT,0,0);
shiftPressEvent.dispatch(this);
}
}
public void startTextSelection() {
try {
WebView.class.getMethod("selectText").invoke(this);
} catch (Exception e) {
try {
WebView.class.getMethod("emulateShiftHeld").invoke(this);
} catch (Exception e1) {
KeyEvent shiftPressEvent = new KeyEvent(0, 0,
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0);
shiftPressEvent.dispatch(this);
Toast.makeText(getContext(), R.string.app_name, Toast.LENGTH_LONG).show();
}
}
}
// Stick the document view and the buttons overlay into a parent view
//Embedding my reader view to webview
layout = new WebView(this);
layout.addView(mDocView);
layout.addView(mButtonsView);
layout.setBackgroundResource(R.drawable.tiled_background);
//layout.setBackgroundResource(R.color.canvas);
setContentView(layout);
}
This is my Reader View:
public class ReaderView extends AdapterView<Adapter>
implements GestureDetector.OnGestureListener,
ScaleGestureDetector.OnScaleGestureListener,
Runnable {
private static final int MOVING_DIAGONALLY = 0;
private static final int MOVING_LEFT = 1;
private static final int MOVING_RIGHT = 2;
private static final int MOVING_UP = 3;
private static final int MOVING_DOWN = 4;
private static final int FLING_MARGIN = 100;
private static final int GAP = 20;
private static final int SCROLL_SPEED = 2;
private static final float MIN_SCALE = 1.0f;
private static final float MAX_SCALE = 5.0f;
private Adapter mAdapter;
private int mCurrent; // Adapter's index for the current view
private boolean mResetLayout;
private final SparseArray<View>
mChildViews = new SparseArray<View>(3);
// Shadows the children of the adapter view
// but with more sensible indexing
private final LinkedList<View>
mViewCache = new LinkedList<View>();
private boolean mUserInteracting; // Whether the user is interacting
private boolean mScaling; // Whether the user is currently pinch zooming
private float mScale = 1.0f;
private int mXScroll; // Scroll amounts recorded from events.
private int mYScroll; // and then accounted for in onLayout
private final GestureDetector
mGestureDetector;
private final ScaleGestureDetector
mScaleGestureDetector;
private final Scroller mScroller;
private int mScrollerLastX;
private int mScrollerLastY;
private boolean mScrollDisabled;
public ReaderView(Context context) {
super(context);
mGestureDetector = new GestureDetector(this);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
mScroller = new Scroller(context);
}
public ReaderView(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(this);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
mScroller = new Scroller(context);
}
public ReaderView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mGestureDetector = new GestureDetector(this);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
mScroller = new Scroller(context);
}
public int getDisplayedViewIndex(ToggleButton bookmark_page, String index_from) {
if (index_from.equals("bookmark_button")) { System.out.println("View_if" + index_from);
bookmark_page.setBackgroundResource(R.drawable.top3hover);
} else { System.out.println("View_else" + index_from);
bookmark_page.setBackgroundResource(R.drawable.top3);
}
return mCurrent;
}
public void setDisplayedViewIndex(int i) {
if (0 <= i && i < mAdapter.getCount()) {
mCurrent = i;
onMoveToChild(i);
mResetLayout = true;
requestLayout();
}
}
public void moveToNext() {
View v = mChildViews.get(mCurrent+1);
if (v != null)
slideViewOntoScreen(v);
}
public void moveToPrevious() {
View v = mChildViews.get(mCurrent-1);
if (v != null)
slideViewOntoScreen(v);
}
public void resetupChildren() {
for (int i = 0; i < mChildViews.size(); i++)
onChildSetup(mChildViews.keyAt(i), mChildViews.valueAt(i));
}
protected void onChildSetup(int i, View v) {}
protected void onMoveToChild(int i) {}
protected void onSettle(View v) {};
protected void onUnsettle(View v) {};
protected void onNotInUse(View v) {};
public View getDisplayedView() {
return mChildViews.get(mCurrent);
}
public void run() {
if (!mScroller.isFinished()) {
mScroller.computeScrollOffset();
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
mXScroll += x - mScrollerLastX;
mYScroll += y - mScrollerLastY;
mScrollerLastX = x;
mScrollerLastY = y;
requestLayout();
post(this);
}
else if (!mUserInteracting) {
// End of an inertial scroll and the user is not interacting.
// The layout is stable
View v = mChildViews.get(mCurrent);
postSettle(v);
}
}
public boolean onDown(MotionEvent arg0) {
mScroller.forceFinished(true);
return true;
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (mScrollDisabled)
return true;
View v = mChildViews.get(mCurrent);
if (v != null) {
Rect bounds = getScrollBounds(v);
switch(directionOfTravel(velocityX, velocityY)) {
case MOVING_LEFT:
if (bounds.left >= 0) {
// Fling off to the left bring next view onto screen
View vl = mChildViews.get(mCurrent+1);
if (vl != null) {
slideViewOntoScreen(vl);
return true;
}
}
break;
case MOVING_RIGHT:
if (bounds.right <= 0) {
// Fling off to the right bring previous view onto screen
View vr = mChildViews.get(mCurrent-1);
if (vr != null) {
slideViewOntoScreen(vr);
return true;
}
}
break;
}
mScrollerLastX = mScrollerLastY = 0;
// If the page has been dragged out of bounds then we want to spring back
// nicely. fling jumps back into bounds instantly, so we don't want to use
// fling in that case. On the other hand, we don't want to forgo a fling
// just because of a slightly off-angle drag taking us out of bounds other
// than in the direction of the drag, so we test for out of bounds only
// in the direction of travel.
//
// Also don't fling if out of bounds in any direction by more than fling
// margin
Rect expandedBounds = new Rect(bounds);
expandedBounds.inset(-FLING_MARGIN, -FLING_MARGIN);
if(withinBoundsInDirectionOfTravel(bounds, velocityX, velocityY)
&& expandedBounds.contains(0, 0)) {
mScroller.fling(0, 0, (int)velocityX, (int)velocityY, bounds.left, bounds.right, bounds.top, bounds.bottom);
post(this);
}
}
return true;
}
public void onLongPress(MotionEvent e) {
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
if (!mScrollDisabled) {
mXScroll -= distanceX;
mYScroll -= distanceY;
requestLayout();
}
return true;
}
public void onShowPress(MotionEvent e) {
}
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
public boolean onScale(ScaleGestureDetector detector) {
float previousScale = mScale;
mScale = Math.min(Math.max(mScale * detector.getScaleFactor(), MIN_SCALE), MAX_SCALE);
float factor = mScale/previousScale;
View v = mChildViews.get(mCurrent);
if (v != null) {
// Work out the focus point relative to the view top left
int viewFocusX = (int)detector.getFocusX() - (v.getLeft() + mXScroll);
int viewFocusY = (int)detector.getFocusY() - (v.getTop() + mYScroll);
// Scroll to maintain the focus point
mXScroll += viewFocusX - viewFocusX * factor;
mYScroll += viewFocusY - viewFocusY * factor;
requestLayout();
}
return true;
}
public boolean onScaleBegin(ScaleGestureDetector detector) {
mScaling = true;
// Ignore any scroll amounts yet to be accounted for: the
// screen is not showing the effect of them, so they can
// only confuse the user
mXScroll = mYScroll = 0;
// Avoid jump at end of scaling by disabling scrolling
// until the next start of gesture
mScrollDisabled = true;
return true;
}
public void onScaleEnd(ScaleGestureDetector detector) {
mScaling = false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//mScaleGestureDetector.onTouchEvent(event);
if (!mScaling)
mGestureDetector.onTouchEvent(event);
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mUserInteracting = true;
}
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
mScrollDisabled = false;
mUserInteracting = false;
View v = mChildViews.get(mCurrent);
if (v != null) {
if (mScroller.isFinished()) {
// If, at the end of user interaction, there is no
// current inertial scroll in operation then animate
// the view onto screen if necessary
slideViewOntoScreen(v);
}
if (mScroller.isFinished()) {
// If still there is no inertial scroll in operation
// then the layout is stable
postSettle(v);
}
}
}
requestLayout();
return true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int n = getChildCount();
for (int i = 0; i < n; i++)
measureView(getChildAt(i));
}
#Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
View cv = mChildViews.get(mCurrent);
Point cvOffset;
if (!mResetLayout) {
// Move to next or previous if current is sufficiently off center
if (cv != null) {
cvOffset = subScreenSizeOffset(cv);
// cv.getRight() may be out of date with the current scale
// so add left to the measured width for the correct position
if (cv.getLeft() + cv.getMeasuredWidth() + cvOffset.x + GAP/2 + mXScroll < getWidth()/2 && mCurrent + 1 < mAdapter.getCount()) {
postUnsettle(cv);
// post to invoke test for end of animation
// where we must set hq area for the new current view
post(this);
mCurrent++;
onMoveToChild(mCurrent);
}
if (cv.getLeft() - cvOffset.x - GAP/2 + mXScroll >= getWidth()/2 && mCurrent > 0) {
postUnsettle(cv);
// post to invoke test for end of animation
// where we must set hq area for the new current view
post(this);
mCurrent--;
onMoveToChild(mCurrent);
}
}
// Remove not needed children and hold them for reuse
int numChildren = mChildViews.size();
int childIndices[] = new int[numChildren];
for (int i = 0; i < numChildren; i++)
childIndices[i] = mChildViews.keyAt(i);
for (int i = 0; i < numChildren; i++) {
int ai = childIndices[i];
if (ai < mCurrent - 1 || ai > mCurrent + 1) {
View v = mChildViews.get(ai);
onNotInUse(v);
mViewCache.add(v);
removeViewInLayout(v);
mChildViews.remove(ai);
}
}
} else {
mResetLayout = false;
mXScroll = mYScroll = 0;
// Remove all children and hold them for reuse
int numChildren = mChildViews.size();
for (int i = 0; i < numChildren; i++) {
View v = mChildViews.valueAt(i);
onNotInUse(v);
mViewCache.add(v);
removeViewInLayout(v);
}
mChildViews.clear();
// post to ensure generation of hq area
post(this);
}
// Ensure current view is present
int cvLeft, cvRight, cvTop, cvBottom;
boolean notPresent = (mChildViews.get(mCurrent) == null);
cv = getOrCreateChild(mCurrent);
// When the view is sub-screen-size in either dimension we
// offset it to center within the screen area, and to keep
// the views spaced out
cvOffset = subScreenSizeOffset(cv);
if (notPresent) {
//Main item not already present. Just place it top left
cvLeft = cvOffset.x;
cvTop = cvOffset.y;
} else {
// Main item already present. Adjust by scroll offsets
cvLeft = cv.getLeft() + mXScroll;
cvTop = cv.getTop() + mYScroll;
}
// Scroll values have been accounted for
mXScroll = mYScroll = 0;
cvRight = cvLeft + cv.getMeasuredWidth();
cvBottom = cvTop + cv.getMeasuredHeight();
if (!mUserInteracting && mScroller.isFinished()) {
Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom));
cvRight += corr.x;
cvLeft += corr.x;
cvTop += corr.y;
cvBottom += corr.y;
} else if (cv.getMeasuredHeight() <= getHeight()) {
// When the current view is as small as the screen in height, clamp
// it vertically
Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom));
cvTop += corr.y;
cvBottom += corr.y;
}
cv.layout(cvLeft, cvTop, cvRight, cvBottom);
if (mCurrent > 0) {
View lv = getOrCreateChild(mCurrent - 1);
Point leftOffset = subScreenSizeOffset(lv);
int gap = leftOffset.x + GAP + cvOffset.x;
lv.layout(cvLeft - lv.getMeasuredWidth() - gap,
(cvBottom + cvTop - lv.getMeasuredHeight())/2,
cvLeft - gap,
(cvBottom + cvTop + lv.getMeasuredHeight())/2);
}
if (mCurrent + 1 < mAdapter.getCount()) {
View rv = getOrCreateChild(mCurrent + 1);
Point rightOffset = subScreenSizeOffset(rv);
int gap = cvOffset.x + GAP + rightOffset.x;
rv.layout(cvRight + gap,
(cvBottom + cvTop - rv.getMeasuredHeight())/2,
cvRight + rv.getMeasuredWidth() + gap,
(cvBottom + cvTop + rv.getMeasuredHeight())/2);
}
invalidate();
}
#Override
public Adapter getAdapter() {
return mAdapter;
}
#Override
public View getSelectedView() {
throw new UnsupportedOperationException("Not supported");
}
#Override
public void setAdapter(Adapter adapter) {
mAdapter = adapter;
mChildViews.clear();
removeAllViewsInLayout();
requestLayout();
}
#Override
public void setSelection(int arg0) {
throw new UnsupportedOperationException("Not supported");
}
private View getCached() {
if (mViewCache.size() == 0)
return null;
else
return mViewCache.removeFirst();
}
private View getOrCreateChild(int i) {
View v = mChildViews.get(i);
if (v == null) {
v = mAdapter.getView(i, getCached(), this);
addAndMeasureChild(i, v);
}
onChildSetup(i, v);
return v;
}
private void addAndMeasureChild(int i, View v) {
LayoutParams params = v.getLayoutParams();
if (params == null) {
params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
addViewInLayout(v, 0, params, true);
mChildViews.append(i, v); // Record the view against it's adapter index
measureView(v);
}
private void measureView(View v) {
// See what size the view wants to be
v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
// Work out a scale that will fit it to this view
float scale = Math.min((float)getWidth()/(float)v.getMeasuredWidth(),
(float)getHeight()/(float)v.getMeasuredHeight());
// Use the fitting values scaled by our current scale factor
v.measure(View.MeasureSpec.EXACTLY | (int)(v.getMeasuredWidth()*scale*mScale),
View.MeasureSpec.EXACTLY | (int)(v.getMeasuredHeight()*scale*mScale));
}
private Rect getScrollBounds(int left, int top, int right, int bottom) {
int xmin = getWidth() - right;
int xmax = -left;
int ymin = getHeight() - bottom;
int ymax = -top;
// In either dimension, if view smaller than screen then
// constrain it to be central
if (xmin > xmax) xmin = xmax = (xmin + xmax)/2;
if (ymin > ymax) ymin = ymax = (ymin + ymax)/2;
return new Rect(xmin, ymin, xmax, ymax);
}
private Rect getScrollBounds(View v) {
// There can be scroll amounts not yet accounted for in
// onLayout, so add mXScroll and mYScroll to the current
// positions when calculating the bounds.
return getScrollBounds(v.getLeft() + mXScroll,
v.getTop() + mYScroll,
v.getLeft() + v.getMeasuredWidth() + mXScroll,
v.getTop() + v.getMeasuredHeight() + mYScroll);
}
private Point getCorrection(Rect bounds) {
return new Point(Math.min(Math.max(0,bounds.left),bounds.right),
Math.min(Math.max(0,bounds.top),bounds.bottom));
}
private void postSettle(final View v) {
// onSettle and onUnsettle are posted so that the calls
// wont be executed until after the system has performed
// layout.
post (new Runnable() {
public void run () {
onSettle(v);
}
});
}
private void postUnsettle(final View v) {
post (new Runnable() {
public void run () {
onUnsettle(v);
}
});
}
private void slideViewOntoScreen(View v) {
Point corr = getCorrection(getScrollBounds(v));
if (corr.x != 0 || corr.y != 0) {
mScrollerLastX = mScrollerLastY = 0;
mScroller.startScroll(0, 0, corr.x, corr.y, 400);
post(this);
}
}
private Point subScreenSizeOffset(View v) {
return new Point(Math.max((getWidth() - v.getMeasuredWidth())/2, 0),
Math.max((getHeight() - v.getMeasuredHeight())/2, 0));
}
private static int directionOfTravel(float vx, float vy) {
if (Math.abs(vx) > 2 * Math.abs(vy))
return (vx > 0) ? MOVING_RIGHT : MOVING_LEFT;
else if (Math.abs(vy) > 2 * Math.abs(vx))
return (vy > 0) ? MOVING_DOWN : MOVING_UP;
else
return MOVING_DIAGONALLY;
}
private static boolean withinBoundsInDirectionOfTravel(Rect bounds, float vx, float vy) {
switch (directionOfTravel(vx, vy)) {
case MOVING_DIAGONALLY: return bounds.contains(0, 0);
case MOVING_LEFT: return bounds.left <= 0;
case MOVING_RIGHT: return bounds.right >= 0;
case MOVING_UP: return bounds.top <= 0;
case MOVING_DOWN: return bounds.bottom >= 0;
default: throw new NoSuchElementException();
}
}
}
In Reader Class, make localbroadcast and implement it in your main Activity
public void onLongPress(MotionEvent e) {
Intent next = new Intent(StringConstant.SEARCH_WORD);
next.putExtra(StringConstant.DOUBLE_TAP_PDF, "true");
LocalBroadcastManager.getInstance(mContext).sendBroadcast(next);
}
This is your broadcast reciever
private BroadcastReceiver mPdfDoubleClickedReciever = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
Log.e("", "mPdfDoubleClickedReciever called");
hideEditedNotes();
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
boolean success = false;
if (pageView != null)
success = pageView.copySelection();
mTopBarMode = TopBarMode.Main;
// showInfo(success ?
// getString(R.string.copied_to_clipboard)
// : getString(R.string.no_text_selected));
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
selectedClipboardText = "";
selectedClipboardText = (String) clipboard.getText();
// Do task here
}
}
};