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
}
}
};
Related
I want my game to exit and go to a separate Activity when the user collides. For example, I want it to go back to my main menu. I've tried adding a Button, new intent method etc and these don't work. I can't find the answer anywhere and i'm not knowledgeable enough to do this as I'm learning. I've trawled the internet but nothing has really helped. Any advice would be awesome. My idea was to change the newgame() method to exit the game?
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;
import java.util.Random;
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
private Threading threading;
private BackgroundImage bg;
public static final int WIDTH = 856;
public static final int HEIGHT = 480;
public static final int MovementSpeed = -8;
private Player player;
private ArrayList<BorderTop> borderTop;
private ArrayList<BorderBottom> borderBottom;
private ArrayList<Smokepuff> smoke;
private ArrayList<Missile> missiles;
private int MaximumBorderHeight;
private int MinimumBorderHeight;
private boolean topDown = true;
private boolean botDown = true;
private int progressDifficulty = 20;
private Random rand = new Random();
private boolean newGameCreated;
private long smokeStartTime;
private long missileStartTime;
public GamePanel(Context context) {
super(context);
getHolder().addCallback(this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
bg = new BackgroundImage(BitmapFactory.decodeResource(getResources(), R.drawable.grassbg1));
player = new Player(BitmapFactory.decodeResource(getResources(), R.drawable.smallcatfinal), 40, 44, 1);
borderTop = new ArrayList<BorderTop>();
borderBottom = new ArrayList<BorderBottom>();
smoke = new ArrayList<Smokepuff>();
missiles = new ArrayList<Missile>();
smokeStartTime= System.nanoTime();
missileStartTime = System.nanoTime();
threading = new Threading(getHolder(), this);
threading.setRunning(true);
threading.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
int counter = 0;
while (retry && counter < 1000) {
counter++;
try {
threading.setRunning(false);
threading.join();
retry = false;
threading = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!player.getPlaying()) {
player.setPlaying(true);
player.setUp(true);
}else{
player.setUp(true);
}
return true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
player.setUp(false);
return true;
}
return super.onTouchEvent(event);
}
public void update() {
if (player.getPlaying()) {
bg.update();
player.update();
MaximumBorderHeight = 30 + player.getScore() / progressDifficulty;
if (MaximumBorderHeight > HEIGHT / 4) MaximumBorderHeight = HEIGHT / 4;
MinimumBorderHeight = 5 + player.getScore() / progressDifficulty;
//check bottom border collision
for (int i = 0; i < borderBottom.size(); i++) {
if (collision(borderBottom.get(i), player))
player.setPlaying(false);
}
//check top border collision
for (int i = 0; i < borderTop.size(); i++) {
if (collision(borderTop.get(i), player))
player.setPlaying(false);
}
this.updateTop();
this.updateBottom();
long missileElapsed = (System.nanoTime() - missileStartTime) / 1000000;
if (missileElapsed > (2000 - player.getScore() / 4)) {
//first missile always goes down the middle
if (missiles.size() == 0) {
missiles.add(new Missile(BitmapFactory.decodeResource(getResources(), R.drawable.
missile), WIDTH + 10, HEIGHT / 2, 45, 15, player.getScore(), 13));
} else {
missiles.add(new Missile(BitmapFactory.decodeResource(getResources(), R.drawable.missile),
WIDTH + 10, (int) (rand.nextDouble() * (HEIGHT - (MaximumBorderHeight * 2)) + MaximumBorderHeight), 45, 15, player.getScore(), 13));
}
//reset timer
missileStartTime = System.nanoTime();
}
//loop through every missile and check collision and remove
for (int i = 0; i < missiles.size(); i++) {
//update missile
missiles.get(i).update();
if (collision(missiles.get(i), player)) {
missiles.remove(i);
player.setPlaying(false);
break;
}
//remove missile if it is way off the screen
if (missiles.get(i).getX() < -100) {
missiles.remove(i);
break;
}
}
long elapsed = (System.nanoTime() - smokeStartTime) / 1000000;
if (elapsed > 120) {
smoke.add(new Smokepuff(player.getX(), player.getY() + 10));
smokeStartTime = System.nanoTime();
}
for (int i = 0; i < smoke.size(); i++) {
smoke.get(i).update();
if (smoke.get(i).getX() < -10) {
smoke.remove(i);
}
}
} else {
newGameCreated = false;
if (!newGameCreated) {
newGame();
}
}
public boolean collision (GameObject a, GameObject b)
{
if (Rect.intersects(a.getRectangle(), b.getRectangle())) {
return true;
}
return false;
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
final float ScaleX = (float) getWidth() / WIDTH*1.f;
final float ScaleY = (float) getHeight() / HEIGHT*1.f;
if (canvas != null) {
final int savedState = canvas.save();
canvas.scale(ScaleX, ScaleY);
bg.draw(canvas);
player.draw(canvas);
for(Smokepuff sp: smoke)
{
sp.draw(canvas);
}
//draw missiles
for(Missile m: missiles)
{
m.draw(canvas);
}
for(BorderTop bt: borderTop)
{
bt.draw(canvas);
}
for(BorderBottom bb: borderBottom)
{
bb.draw(canvas);
}
canvas.restoreToCount(savedState);
}
}
public void updateBottom() {
if (player.getScore() % 40 == 0) {
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(), R.drawable.brick),
borderBottom.get(borderBottom.size() - 1).getX() + 20, (int) ((rand.nextDouble()
* MaximumBorderHeight) + (HEIGHT - MaximumBorderHeight))));
}
//update bottom border
for (int i = 0; i < borderBottom.size(); i++) {
borderBottom.get(i).update();
//if border is moving off screen, remove it and add a corresponding new one
if (borderBottom.get(i).getX() < -20) {
borderBottom.remove(i);
//determine if border will be moving up or down
if (borderBottom.get(borderBottom.size() - 1).getY() <= HEIGHT - MaximumBorderHeight) {
botDown = true;
}
if (borderBottom.get(borderBottom.size() - 1).getY() >= HEIGHT - MinimumBorderHeight) {
botDown = false;
}
if (botDown) {
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(),R.drawable.brick
), borderBottom.get(borderBottom.size() - 1).getX() + 20, borderBottom.get(borderBottom.size() - 1
).getY() + 1));
} else {
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(), R.drawable.brick
), borderBottom.get(borderBottom.size() - 1).getX() + 20, borderBottom.get(borderBottom.size() - 1
).getY() - 1));
}
}
}
}
public void updateTop()
{
if (player.getScore() % 50 == 0) {
borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(), R.drawable.brick), borderTop.get(borderTop.size() - 1).getX() + 20, 0, (int) ((rand.nextDouble() * (MaximumBorderHeight)) + 1)));
}
for (int i = 0; i < borderTop.size(); i++) {
borderTop.get(i).update();
if (borderTop.get(i).getX() < -20) {
borderTop.remove(i);
if (borderTop.get(borderTop.size() - 1).getHeight() >= MaximumBorderHeight) {
topDown = false;
}
if (borderTop.get(borderTop.size() - 1).getHeight() <= MinimumBorderHeight) {
topDown = true;
}
if (topDown) {
borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(), R.drawable.brick), borderTop.get(borderTop.size() - 1).getX() + 20, 0, borderTop.get(borderTop.size() - 1).getHeight() + 1));
} else {
borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(), R.drawable.brick), borderTop.get(borderTop.size() - 1).getX() + 20, 0, borderTop.get(borderTop.size() - 1).getHeight() - 1));
}
}
}
}
public void newGame() {
borderBottom.clear();
borderTop.clear();
missiles.clear();
smoke.clear();
MinimumBorderHeight = 5;
MaximumBorderHeight = 30;
player.resetDY();
player.resetScore();
player.setY(HEIGHT/2);
//create initial borders
//initial top border
for(int i = 0; i*20<WIDTH+40;i++)
{
// first top border create
if(i==0)
{borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(),R.drawable.brick
),i*20,0, 10));
}
else
{
borderTop.add(new BorderTop(BitmapFactory.decodeResource(getResources(),R.drawable.brick
),i*20,0, borderTop.get(i-1).getHeight()+1));
}
}
//initial bottom border
for(int i = 0; i*20<WIDTH+40; i++)
{
//first border ever created
if(i==0)
{
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(),R.drawable.brick)
,i*20,HEIGHT - MinimumBorderHeight));
}
//adding borders until the initial screen is filed
else
{
borderBottom.add(new BorderBottom(BitmapFactory.decodeResource(getResources(), R.drawable.brick),
i * 20, borderBottom.get(i - 1).getY() - 1));
}
}
newGameCreated = true;
}
}
I want to put marker on image with below functionality
-Dynamically adding multiple markers on image with zoom and scroll functionality on image.
-Blink animation on marker after added on image.
-Marker can be click-able and drag & drop on image.
-Marker's x & y position on image to sync same with other devices
I have used https://github.com/davemorrissey/subsampling-scale-image-view library
Java Code :
public class PinMarkerView extends SubsamplingScaleImageView implements View.OnTouchListener {
private PointF sPin;
private Bitmap pin;
private int resId;
public float vX;
public float vY;
private PointF vPrevious;
private PointF vStart;
private boolean drawing = false;
private boolean markerTouch = false;
private int strokeWidth;
private ArrayList<MapPins> allPins = new ArrayList<MapPins>();
private ArrayList<DrawPins> drawnPins = new ArrayList<DrawPins>();
public PinView(Context context) {
this(context, null);
}
public PinView(Context context, AttributeSet attr) {
super(context, attr);
// initialise();
}
public void setPin(PointF sPin, #DrawableRes int resid, String extras) {
MapPins mapPins = new MapPins();
mapPins.setPointF(sPin);
mapPins.setResId(resid);
mapPins.setExtrasData(extras);
mapPins.setX(sPin.x);
mapPins.setY(sPin.y);
allPins.add(mapPins);
//this.sPin = sPin;
// this.resId = resid;
initialise();
invalidate();
}
public PointF getPin() {
return sPin;
}
public Bitmap getMarker() {
return pin;
}
private void initialise() {
setOnTouchListener(this);
float density = getResources().getDisplayMetrics().densityDpi;
strokeWidth = (int) (density / 60f);
for (int i = 0; i < allPins.size(); i++) {
MapPins mapPins = allPins.get(i);
Bitmap localpin = BitmapFactory.decodeResource(this.getResources(), mapPins.getResId());
float w = (density / 100f) * localpin.getWidth();
float h = (density / 100f) * localpin.getHeight();
//pin = Bitmap.createScaledBitmap(pin, (int) w, (int) h, true);
pin = Bitmap.createScaledBitmap(localpin, localpin.getWidth(), localpin.getHeight(), true);
mapPins.setCreatedBitmap(pin);
allPins.set(i, mapPins);
//-------
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Don't draw pin before image is ready so it doesn't move around during setup.
if (!isReady()) {
return;
}
Paint paint = new Paint();
paint.setAntiAlias(true);
for (int i = 0; i < allPins.size(); i++) {
MapPins mapPins = allPins.get(i);
if (mapPins.getPointF() != null && mapPins.getCreatedBitmap() != null) {
PointF vPin = sourceToViewCoord(mapPins.getPointF());
vX = vPin.x - (mapPins.getCreatedBitmap().getWidth() / 2);
vY = vPin.y - mapPins.getCreatedBitmap().getHeight();
canvas.drawBitmap(mapPins.getCreatedBitmap(), vX, vY, paint);
}
}
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
setMaxScale(5f);
return false;
}
#Override
public boolean onTouchEvent(#NonNull MotionEvent event) {
/* if (isZoomEnabled()) {
return super.onTouchEvent(event);
}*/
boolean consumed = false;
int touchCount = event.getPointerCount();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_1_DOWN:
vStart = new PointF(event.getX(), event.getY());
vPrevious = new PointF(event.getX(), event.getY());
getPinIdByPoint(vStart, viewToSourceCoord(event.getX(), event.getY()));
handleActionDown((int) event.getX(), (int) event.getY());
break;
case MotionEvent.ACTION_POINTER_2_DOWN:
// Abort any current drawing, user is zooming
vStart = null;
vPrevious = null;
break;
case MotionEvent.ACTION_MOVE:
if (markerTouch) {
setPanEnabled(false);
PointF sCurrentF = viewToSourceCoord(event.getX(), event.getY());
PointF sCurrent = new PointF(sCurrentF.x, sCurrentF.y);
PointF sStart = vStart == null ? null : new PointF(viewToSourceCoord(vStart).x, viewToSourceCoord(vStart).y);
if (touchCount == 1 && vStart != null) {
float vDX = Math.abs(event.getX() - vPrevious.x);
float vDY = Math.abs(event.getY() - vPrevious.y);
if (vDX >= strokeWidth * 5 || vDY >= strokeWidth * 5) {
if (sPin == null) {
sPin = sStart;
}
sPin = sCurrent;
vPrevious.x = event.getX();
vPrevious.y = event.getY();
drawing = true;
}
consumed = true;
invalidate();
} else if (touchCount == 1) {
// Consume all one touch drags to prevent odd panning effects handled by the superclass.
consumed = true;
}
} else {
return super.onTouchEvent(event);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
invalidate();
setPanEnabled(true);
drawing = false;
markerTouch = false;
vPrevious = null;
vStart = null;
}
// Use parent to handle pinch and two-finger pan.
return consumed || super.onTouchEvent(event);
}
public void handleActionDown(int eventX, int eventY) {
if (eventX >= (sPin.x - pin.getWidth()) && (eventX <= (sPin.x + pin.getWidth()))) {
if (eventY >= (sPin.y - pin.getHeight()) && (sPin.y <= (sPin.y + pin.getHeight()))) {
markerTouch = true;
} else {
markerTouch = false;
}
} else {
markerTouch = false;
}
}
public int getPinIdByPoint(PointF tappedCoordinate, PointF deeplinkCoordinate) {
for (int i = allPins.size() - 1; i >= 0; i--) {
MapPins dPin = allPins.get(i);
int blockWidth = dPin.getCreatedBitmap().getWidth();
int blockHeight = dPin.getCreatedBitmap().getHeight();
int deeplinkX = (int) (deeplinkCoordinate.x - (dPin.getCreatedBitmap().getWidth() / 2));
int deeplinkY = (int) (deeplinkCoordinate.y - dPin.getCreatedBitmap().getHeight());
// center coordinate -/+ blockWidth actually sets touchable area to 2x icon size
if (tappedCoordinate.x >= deeplinkX - blockWidth && tappedCoordinate.x <= deeplinkX + blockWidth &&
tappedCoordinate.y >= deeplinkY - blockHeight && tappedCoordinate.y <= deeplinkY + blockHeight) {
sPin = dPin.getPointF();
pin = dPin.getCreatedBitmap();
return dPin.getId();
}
}
return -1; //negative no means no pin selected
}
}
Currently, I am able to add multiple marker, but I am facing issue of marker click and dragging on image.
I am creating an application. If the custom View goes off the screen, a method is called. Here is my code for the custom View.
public class CustomView extends View {
private boolean bubbleOver;
private static final int BITMAP_SIZE = 64;
private static final int REFRESH_RATE = 40;
private final Paint mPainter = new Paint();
private ScheduledFuture<?> mMoverFuture;
private int mScaledBitmapWidth;
private Bitmap mScaledBitmap;
// location, speed and direction of the bubble
private float mXPos, mYPos, mDx, mDy, mRadius, mRadiusSquared;
private long mRotate, mDRotate;
CustomView (Context context, float x, float y) {
super (context);
// Create a new random number generator to randomize size, rotation, speed and direction
Random r = new Random ();
// Creates the bubble bitmap for this BubbleView
createScaledBitmap (r);
// Radius of the Bitmap
mRadius = mScaledBitmapWidth / 2;
mRadiusSquared = mRadius * mRadius;
// Adjust position to center the bubble under user's finger
mXPos = x - mRadius;
mYPos = y - mRadius;
// Set the BubbleView's speed and direction
setSpeedAndDirection(r);
// Set the BubbleView's rotation
setRotation(r);
mPainter.setAntiAlias(true);
}
private void setRotation(Random r) {
if (speedMode == RANDOM) {
// TODO - set rotation in range [1..3]
mDRotate = r.nextInt (3) + 1;
} else {
mDRotate = 0;
}
}
private void setSpeedAndDirection(Random r) {
// Used by test cases
switch (speedMode) {
case SINGLE:
mDx = 20;
mDy = 20;
break;
case STILL:
// No speed
mDx = 0;
mDy = 0;
break;
default:
// Limit movement speed in the x and y direction to [-3..3] pixels per movement.
mDx = r.nextFloat() * 6.0f - 3.0f;
mDy = r.nextFloat() * 6.0f - 3.0f;
}
}
private void createScaledBitmap (Random r) {
if (speedMode != RANDOM) {
mScaledBitmapWidth = BITMAP_SIZE * 3;
} else {
mScaledBitmapWidth = (r.nextInt(3) + 1) * BITMAP_SIZE;
}
mScaledBitmap = Bitmap.createScaledBitmap(mBitmap, mScaledBitmapWidth, mScaledBitmapWidth, true);
}
// Start moving the BubbleView & updating the display
private void start () {
// Creates a WorkerThread
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
// Execute the run() in Worker Thread every REFRESH_RATE milliseconds. Save reference to this job in mMoverFuture
mMoverFuture = executor.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
if (moveWhileOnScreen()) {
stop (false);
} else {
BubbleView.this.postInvalidate();
}
}
}, 0, REFRESH_RATE, TimeUnit.MILLISECONDS);
}
// Returns true if the BubbleView intersects position (x,y)
private synchronized boolean intersects(float x, float y) {
// TODO - Return true if the BubbleView intersects position (x,y)
if ((mXPos <= x) && (x <= mXPos + mScaledBitmapWidth) && (mYPos <= y) && (y <= mYPos + mScaledBitmapWidth)) {
return true;
}
return false;
}
// Cancel the Bubble's movement. Remove Bubble from mFrame.
// Play pop sound if the BubbleView was popped
private void stop (final boolean wasPopped) {
if (null != mMoverFuture && !mMoverFuture.isDone()) {
mMoverFuture.cancel(true);
}
// This work will be performed on the UI Thread
mFrame.post(new Runnable() {
#Override
public void run() {
mFrame.removeView(BubbleView.this);
if (wasPopped) {
mSoundPool.play(mSoundID, mStreamVolume, mStreamVolume, 1, 0, 1f);
}
}
});
}
// Change the Bubble's speed and direction
private synchronized void deflect(float velocityX, float velocityY) {
mDx = velocityX / REFRESH_RATE;
mDy = velocityY / REFRESH_RATE;
}
// Draw the Bubble at its current location
#Override
protected synchronized void onDraw(Canvas canvas) {
canvas.save();
mRotate += mDRotate;
canvas.rotate(mRotate, mXPos + (mScaledBitmapWidth / 2), mYPos + (mScaledBitmapWidth / 2));
canvas.drawBitmap(mScaledBitmap, mXPos, mYPos, mPainter);
canvas.restore();
}
// Returns true if the BubbleView is still on the screen after the move operation
private synchronized boolean moveWhileOnScreen() {
mXPos += mDx;
mYPos += mDy;
return isOutOfView();
}
// Return true if the BubbleView is off the screen after the move operation
private boolean isOutOfView() {
if ((mXPos + mDisplayWidth < 0) || (mYPos + mDisplayHeight < 0) || (mXPos> mDisplayWidth) || (mYPos > mDisplayHeight)) {
loseGame();
return true;
}
return false;
}
}
When the View goes off the screen, loseGame() is not called. Only if another CustomView is created, loseGame() is called.
You have wrong sum to check, try with mScaledBitmapWidth not the mDisplayWidth.
if ((mXPos + mScaledBitmapWidth < 0)
|| (mYPos + mScaledBitmapWidth < 0)
|| (mXPos> mDisplayWidth)
|| (mYPos > mDisplayHeight)
{
loseGame();
return true;
}
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;
}
The wheel View (CircleView) is working fine in major of devices but this error coming from S4 and Note 3 devices.
The touch is getting deducted but the that not fall under the weidgetregion.
false - 1 has to be true - 1
Region Log is:
My Circle View code is
public class CircleView extends View implements OnTouchListener{
boolean firstTime = false;
private List<CircleViewBean> mMenuEntries = new ArrayList<CircleViewBean>();
private OnCellTouchListener mOnCellTouchListener = null;
public interface OnCellTouchListener {
public void onTouch(Wedge cell);
}
private Shader mShader;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private float screen_density = getContext().getResources().getDisplayMetrics().density;
//Radius of inner ring size
private int mMinSize = scalePX(60);
//Radius of outer ring size
private int mMaxSize = scalePX(170);
private int mWedgeQty = 6;
//Center X location of Radial Menu
private int xPosition = scalePX(120);
//Center Y location of Radial Menu
private int yPosition = scalePX(120);
int touchIndex = -1;
private Wedge[] mWedges;
private RectF mViewRect = new RectF();
private int scalePX( int dp_size )
{
return (int) (dp_size * screen_density + 0.5f);
}
public CircleView(Context context) {
this(context, null);
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
HashMap<String, String> device = Constants.getDeviceDetails(getResources().getDisplayMetrics().heightPixels, getResources().getDisplayMetrics().widthPixels);
mMinSize = Integer.parseInt(device.get("in_arc"));
mMaxSize = Integer.parseInt(device.get("out_arc"));
setBackgroundResource(R.drawable.centre_wheel);
}
private void determineWedges() {
int entriesQty = mMenuEntries.size();
if ( entriesQty > 0) {
mWedgeQty = entriesQty;
float degSlice = 360 / mWedgeQty;
float start_degSlice = 270 - (degSlice/2);
//calculates where to put the images
this.mWedges = new Wedge[mWedgeQty];
double mid = 0, min = 0, max = 0;
for(int i = 0; i < this.mWedges.length; i++) {
this.mWedges[i] = new Wedge(xPosition, yPosition, mMinSize, mMaxSize, (i
* degSlice)+start_degSlice, degSlice, mMenuEntries.get(i).getIndex());
mid = this.mWedges[i].midValue = normalizeAngle( ((i * degSlice) + start_degSlice + degSlice) / 2 );
min = normalizeAngle( (i * degSlice) + start_degSlice );
max = normalizeAngle( (i * degSlice) + start_degSlice + degSlice);
this.mWedges[i].minValue = min;
this.mWedges[i].midValue = mid;
this.mWedges[i].maxValue = max;
mViewRect.union( new RectF( mWedges[i].getWedgeRegion().getBounds() ) );
}
mShader = new RadialGradient(xPosition, yPosition, mMaxSize, new int[] { 0xff595756, 0xffCCC5C3, 0xf878280}, null, Shader.TileMode.MIRROR);
invalidate();
}
}
#Override
public void onDraw(Canvas canvas) {
if(!firstTime){
firstTime = true;
this.xPosition = (int) (getWidth()/2f);
this.yPosition = (int) (getHeight()/2f);
determineWedges();
}
canvas.scale(getWidth() / mViewRect.width(), getHeight() / mViewRect.width(), xPosition, yPosition);
//Saving the canvas and later restoring it so only this image will be rotated.
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.restore();
canvas.save();
canvas.restore();
mPaint.setShader( mShader );
}
private double normalizeAngle(double angle) {
if(angle >= 0) {
while( angle > 360 ) {
angle -= 360;
}
}
else {
while( angle < -360) {
angle += 360;
}
}
return angle;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int wmode = MeasureSpec.getMode(widthMeasureSpec);
int hmode = MeasureSpec.getMode(heightMeasureSpec);
int wsize = MeasureSpec.getSize(widthMeasureSpec);
int hsize = MeasureSpec.getSize(heightMeasureSpec);
int width = (int)mViewRect.width();
int height = (int) mViewRect.height();
if (wmode == MeasureSpec.EXACTLY) {
width = wsize;
}
if (hmode == MeasureSpec.EXACTLY) {
height = hsize;
}
this.setMeasuredDimension(width, height);
invalidate();
}
public class Wedge extends Path {
private int x, y;
private int InnerSize, OuterSize;
private float StartArc;
private float ArcWidth;
private Region mWedgeRegion;
private int index=0;
public double minValue;
public double midValue;
public double maxValue;
private Wedge(int x, int y, int InnerSize, int OuterSize, float StartArc, float ArcWidth, int category) {
super();
this.index = category;
if (StartArc >= 360) {
StartArc = StartArc-360;
}
minValue = midValue = maxValue = 0;
mWedgeRegion = new Region();
this.x = x; this.y = y;
this.InnerSize = InnerSize;
this.OuterSize = OuterSize;
this.StartArc = StartArc;
this.ArcWidth = ArcWidth;
this.buildPath();
}
public int getCategoryIndex(){
return this.index;
}
public String toString() {
return minValue + " " + midValue + " " + maxValue;
}
/**
*
* #return the bottom rect that will be used for intersection
*/
public Region getWedgeRegion() {
return mWedgeRegion;
}
private void buildPath() {
final RectF rect = new RectF();
final RectF rect2 = new RectF();
//Rectangles values
rect.set(this.x-this.InnerSize, this.y-this.InnerSize, this.x+this.InnerSize, this.y+this.InnerSize);
rect2.set(this.x-this.OuterSize, this.y-this.OuterSize, this.x+this.OuterSize, this.y+this.OuterSize);
this.reset();
//this.moveTo(100, 100);
this.arcTo(rect2, StartArc, ArcWidth);
this.arcTo(rect, StartArc+ArcWidth, -ArcWidth);
this.close();
mWedgeRegion.setPath( this, new Region(0,0,480,800) );
}
}
public boolean addMenuEntry(CircleViewBean menuEntry) {
mMenuEntries.add(menuEntry);
return true;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
if(mOnCellTouchListener!=null && touchIndex >-1){
int i=0;
for(Wedge day : mWedges) {
if(day.getWedgeRegion().getBounds().contains((int)event.getX(), (int)event.getY()) && touchIndex==i) {
mOnCellTouchListener.onTouch(mWedges[touchIndex]);
break;
}
i++;
}
}
}else if(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE){
int i=0;
for(Wedge day : mWedges) {
if(day.getWedgeRegion().getBounds().contains((int)event.getX(), (int)event.getY())) {
touchIndex = i;
setBackgroundResource(mMenuEntries.get(touchIndex).getIcon());
}
i++;
}
}
return true;
}
public void setOnCellTouchListener(OnCellTouchListener p) {
mOnCellTouchListener = p;
}
public boolean onTouch(View v, MotionEvent event) {
return false;
}
}
First of all, look at line 307. Learn how to read crash logs because it says exactly on what line the crash is, and then it shouldn't be too hard too determine what is wrong.
Not knowing what line it is I guess that mWedges might be null. in the onTouch you do for(Wedge day : mWedges) but it is not guaranteed that is isn't null there. You should check before you do that if it is null.
You put it to a non null value in determineWedges but only when there is at least 1 mMenuEntries. So when there are no entries when you do an onTouch it will crash.
At last i found my mistake in this code that it is working in mdpi and htpi and not in xxhdpi the reason is
mWedgeRegion.setPath( this, new Region(0,0,480,800) );
The bound exceeds the circle size, i mean the xxhdpi draws an circle with 1000x1000 values, so i made this too like this (max values)
mWedgeRegion.setPath( this, new Region(0,0,720,1200) )