অ্যান্ড্রয়েড: স্পর্শ সরানোর উপর একটি দর্শন সরান (ACTION_MOVE)


177

আমি একটি সাধারণ নিয়ন্ত্রণ করতে চাই: ভিতরে একটি দৃশ্য সহ একটি ধারক। আমি যদি ধারকটি স্পর্শ করি এবং আমি আঙুলটি সরিয়ে রাখি, আমি আমার আঙুলটি অনুসরণ করতে ভিউটি সরাতে চাই।

আমার কোন ধরণের পাত্র (লেআউট) ব্যবহার করা উচিত? কিভাবে এই কাজ করতে?

আমার কোনও পৃষ্ঠ ব্যবহার করার দরকার নেই, তবে একটি সরল বিন্যাস।


এখানে উদাহরণস্বরূপ thegeekyland.blogspot.com/2015/12/…
আর্লিন্ড

উত্তর:


235

এটার মতো কিছু:

public class MyActivity extends Activity implements View.OnTouchListener {

TextView _view;
ViewGroup _root;
private int _xDelta;
private int _yDelta;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    _root = (ViewGroup)findViewById(R.id.root);

    _view = new TextView(this);
    _view.setText("TextView!!!!!!!!");

    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(150, 50);
    layoutParams.leftMargin = 50;
    layoutParams.topMargin = 50;
    layoutParams.bottomMargin = -250;
    layoutParams.rightMargin = -250;
    _view.setLayoutParams(layoutParams);

    _view.setOnTouchListener(this);
    _root.addView(_view);
}

public boolean onTouch(View view, MotionEvent event) {
    final int X = (int) event.getRawX();
    final int Y = (int) event.getRawY();
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
            _xDelta = X - lParams.leftMargin;
            _yDelta = Y - lParams.topMargin;
            break;
        case MotionEvent.ACTION_UP:
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            break;
        case MotionEvent.ACTION_POINTER_UP:
            break;
        case MotionEvent.ACTION_MOVE:
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
            layoutParams.leftMargin = X - _xDelta;
            layoutParams.topMargin = Y - _yDelta;
            layoutParams.rightMargin = -250;
            layoutParams.bottomMargin = -250;
            view.setLayoutParams(layoutParams);
            break;
    }
    _root.invalidate();
    return true;
}}

ইন main.xmlশুধু RelativeLayoutসঙ্গে@+id/root


1
@ অ্যাপজার: চমৎকার কাজ !! তবে আমি অবাক হয়েছি কেন আপনি layoutPrarms.rightMargin = -250এবং একই সাথে রাখেন bottomMargin!! তুমি কি এটা ব্যাখ্যা করতে পারবে? যাই হোক, আপনাকে অনেক ধন্যবাদ!!
কিংফিশার ফিউক

1
যদি আমার স্মৃতিটি এই মানগুলি ব্যতীত আমাকে পরিবেশন করে, দৃশ্যটি ডান বা নীচে সরানোর সময় সংকোচিত হবে। আপনি এগুলি পরিবর্তন করার চেষ্টা করতে পারেন এবং কী ঘটে তা দেখতে পারেন।
ভায়াচ্লাভ শাইলকিন

1
তাদের চূড়ান্ত হতে হবে না। এই ভেরিয়েবলগুলি পুনরায় জমা না দেওয়ার জন্য আমি তাদের চূড়ান্ত করেছিলাম।
ভায়াচ্লাভ শাইলকিন

1
এটি দুর্দান্ত কাজ করছে তবে পর্দার বাইরে থেকে সরানো কী কী উপায় আছে যার অর্থ কেবল পর্দার গণ্ডির ভিতরে চলে আসা উচিত ..
দাউদ আরফিন

2
@ ভাইচেস্লাভশিলকিন এই কোডটিতে আমার একমাত্র সমস্যাটি হ'ল আমি এক্সএমএল ফাইল থেকে সরানোর জন্য লেআউটগুলি স্ফীত করতে পারিনি। এটি কি আসলে কোডটির ইস্যু বা আমার অজ্ঞতার কারণে মিস করছি?
ব্যবহারকারী 2498079

356

ভিউপ্রপার্টি অ্যানিম্যাটরের সাথে এটি করার জন্য আমি একটি সহজ পদ্ধতির সন্ধান পেয়েছি:

float dX, dY;

@Override
public boolean onTouch(View view, MotionEvent event) {

    switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:

            dX = view.getX() - event.getRawX();
            dY = view.getY() - event.getRawY();
            break;

        case MotionEvent.ACTION_MOVE:

            view.animate()
                    .x(event.getRawX() + dX)
                    .y(event.getRawY() + dY)
                    .setDuration(0)
                    .start();
            break;
        default:
            return false;
    }
    return true;
}

3
@ ruan65 আমি কি আমার স্ক্রিনটি টেনে না নেওয়ার জন্য ভিউটি সীমাবদ্ধ রাখতে পারি?
ধীরাজ দেবকার

13
যদি কেউ আমার মতোই বিভ্রান্ত হয়ে পড়েছিল তবে কেন এটি কাজ করে তা কেবল জেনে নিন যে getX () ভিউয়ের সাথে সম্পর্কিত একটি এক্স সমন্বয় ফিরিয়ে দেয়, যখন getRawX () ডিভাইসের স্ক্রিনের তুলনায় একটি পরম স্থানাঙ্ক ফেরত দেয়। stackoverflow.com/a/20636236/4258848
আমের Mograbi

2
জেনিয়াস, সবেমাত্র কিছু সীমা পরীক্ষা করা যুক্ত করেছে এবং এটি একটি স্লাইডার বোতামের অনুভূমিক স্ক্রোলিংয়ের জন্য দুর্দান্ত কাজ করে
মেনম্যান

2
যদিও এটি পূর্ববর্তী উত্তরের মতো কাজ করে তবে আপনার সরানো ইভেন্টে অনুবাদ এক্স এবং অনুবাদ ওয়াই পদ্ধতি ব্যবহার করা আরও ভাল। অবস্থানটি স্থিতিশীল করতে "আপ" ইভেন্টে ভিউটির বিন্যাস বৈশিষ্ট্যগুলি সেট করুন। অনুবাদ পদ্ধতিগুলি আপনার ফোনের হার্ডওয়্যার স্তর ব্যবহার করছে। বিন্যাসের বৈশিষ্ট্য নেই।
গিলিস হাসনুট

3
0 এর সময়কালের অ্যানিমেশন প্রয়োগ করার পরিবর্তে আমরা setXএবং setYসরাসরি ব্যবহার করতে পারি
ব্যবহারকারী 1032613

11

@ অ্যান্ড্রে পদ্ধতির অনুসরণ করে আপনি যদি ভিউটিকে এর কেন্দ্র থেকে সরিয়ে নিতে চান তবে আপনাকে কেবল দেখার অর্ধেক উচ্চতা এবং প্রস্থকে চলাচলে বিয়োগ করতে হবে।

float dX, dY;

@Override
public boolean onTouchEvent(View view, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            dX = view.getX() - event.getRawX();
            dY = view.getY() - event.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:
            view.animate()
                .x(event.getRawX() + dX - (view.getWidth() / 2))
                .y(event.getRawY() + dY - (view.getHeight() / 2))
                .setDuration(0)
                .start();
            break;
        default:
            return false;
    }
    return true;
}

3

কোটলিনে একই বাস্তবায়ন

    rightPanel.setOnTouchListener(View.OnTouchListener { view, event ->
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {

                rightDX = view!!.x - event.rawX
                // rightDY = view!!.getY() - event.rawY;

            }
            MotionEvent.ACTION_MOVE -> {

                var displacement = event.rawX + rightDX

                view!!.animate()
                        .x(displacement)
                        // .y(event.getRawY() + rightDY)
                        .setDuration(0)
                        .start()
            }
            else -> { // Note the block
                return@OnTouchListener false
            }
        }
        true
 })

এই উত্তর সম্পর্কে মজার বিষয় হ'ল আমি এটি লিখেছিলাম এবং এটি আমাকে একাধিকবার সহায়তা করেছিল।
हितেশ সাহু

3

ধারকটিকে স্পর্শ করুন এবং দৃশ্যটি আপনার আঙুলটি অনুসরণ করবে।

এক্সএমএল কোড

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/floating_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <ImageView
      android:id="@+id/btn_chat"
      android:layout_width="42dp"
      android:layout_height="42dp"
      />

<LinearLayout>

জাভা কোড

public class DashBoardActivity extends Activity implements View.OnClickListener, View.OnTouchListener {

    float dX;
    float dY;
    int lastAction;
    LinearLayout floatingLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_dashboard);

        floatingLayout = findViewById(R.id.floating_layout);
        floatingLayout.setOnTouchListener(this);    



     @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                dX = view.getX() - event.getRawX();
                dY = view.getY() - event.getRawY();
                lastAction = MotionEvent.ACTION_DOWN;
                break;

            case MotionEvent.ACTION_MOVE:
                view.setY(event.getRawY() + dY);
                view.setX(event.getRawX() + dX);
                lastAction = MotionEvent.ACTION_MOVE;
                break;

            case MotionEvent.ACTION_UP:
                if (lastAction == MotionEvent.ACTION_DOWN)
                    Toast.makeText(DashBoardActivity.this, "Clicked!", Toast.LENGTH_SHORT).show();
                break;

            default:
                return false;
        }
        return true;
    }
}

2

আপনার মতামত সরাতে আমি view.translationX এবং দেখুন.translationY ব্যবহার করার পরামর্শ দিচ্ছি।

কোটলিন স্নিপেট:

yourView.translationX = xTouchCoordinate
yourView.translationY = yTouchCoordinate

2

একটি কাস্টম টাচ শ্রোতা শ্রেণি তৈরি করুন (কোটলিনে):

(এই কোডটি আপনার দৃষ্টিভঙ্গিকে এর প্যারেন্ট ভিউ থেকে টেনে আনতে বাধা দেয়)

class CustomTouchListener(
  val screenWidth: Int, 
  val screenHeight: Int
) : View.OnTouchListener {
    private var dX: Float = 0f
    private var dY: Float = 0f

    override fun onTouch(view: View, event: MotionEvent): Boolean {

        val newX: Float
        val newY: Float

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                dX = view.x - event.rawX
                dY = view.y - event.rawY
            }
            MotionEvent.ACTION_MOVE -> {

                newX = event.rawX + dX
                newY = event.rawY + dY

                if ((newX <= 0 || newX >= screenWidth - view.width) || (newY <= 0 || newY >= screenHeight - view.height)) {
                    return true
                }

                view.animate()
                    .x(newX)
                    .y(newY)
                    .setDuration(0)
                    .start()
            }
        }
        return true
    }
}

এটি কিভাবে ব্যবহার করতে?

parentView.viewTreeObserver.addOnGlobalLayoutListener { view.setOnTouchListener(CustomTouchListener(parentView.width, parentView.height)) }

parentView আপনার দেখার পিতামাতা


1

নীচের কোডে, আমি RegionView( গিট ) নামক একটি কিছু তৈরি করেছি , যা এর নেস্টেড বাচ্চাদের প্রত্যেকের জন্য ড্রাগ এবং জুম অপারেশন পরিচালনার জন্য দায়ী পুনরায় ব্যবহারযোগ্য ধারক।

এখানে, আমরা নিপূণভাবে topএবং leftএকটি শিশুর কোফিসিয়েন্টস View's LayoutParamsডায়াগ্রাম সম্পর্কে অনুকরণ আন্দোলনে। ড্র্যাগ অপারেশন হিসাবে কী বোঝে এবং কী স্কেল অপারেশন হতে হবে তা হ্যান্ডলিংয়ের ব্যাখ্যাকে ডাকা করে, আমরা কোনও সন্তানের নির্ভরযোগ্য হেরফের সরবরাহ করতে পারি View

package com.zonal.regionview;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Vibrator;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.RelativeLayout;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Alexander Thomas (@Cawfree) on 20/07/2017.
 */

/** Enables users to customize Regions Of Interest on a Canvas. */
public class RegionView extends RelativeLayout implements View.OnTouchListener, GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener {

    /* Member Variables. */
    private final GestureDetector      mGestureDetector;
    private final ScaleGestureDetector mScaleGestureDetector;
    private final Map<Integer, View>   mViewMap;
    private       boolean              mScaling;
    private       float                mScale;
    private       boolean              mWrapContent;
    private       boolean              mDropOnScale;

    public RegionView(Context context) {
        // Implement the Parent.
        super(context);
        // Initialize Member Variables.
        this.mGestureDetector      = new GestureDetector(context, this);
        this.mViewMap              = new HashMap<>();
        this.mScaleGestureDetector = new ScaleGestureDetector(context, this);
        this.mScaling              = false;
        this.mScale                = Float.NaN;
        this.mWrapContent          = false;
        this.mDropOnScale          = false;
        // Register ourself as the OnTouchListener.
        this.setOnTouchListener(this);
    }

    public RegionView(Context context, @Nullable AttributeSet attrs) {
        // Implement the Parent.
        super(context, attrs);
        // Initialize Member Variables.
        this.mGestureDetector      = new GestureDetector(context, this);
        this.mViewMap              = new HashMap<>();
        this.mScaleGestureDetector = new ScaleGestureDetector(context, this);
        this.mScaling              = false;
        this.mWrapContent          = false;
        this.mDropOnScale          = false;
        // Register ourself as the OnTouchListener.
        this.setOnTouchListener(this);
    }

    public RegionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        // Implement the Parent.
        super(context, attrs, defStyleAttr);
        // Initialize Member Variables.
        this.mGestureDetector      = new GestureDetector(context, this);
        this.mViewMap              = new HashMap<>();
        this.mScaleGestureDetector = new ScaleGestureDetector(context, this);
        this.mScaling              = false;
        this.mWrapContent          = false;
        this.mDropOnScale          = false;
        // Register ourself as the OnTouchListener.
        this.setOnTouchListener(this);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public RegionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        // Implement the Parent.
        super(context, attrs, defStyleAttr, defStyleRes);
        // Initialize Member Variables.
        this.mGestureDetector      = new GestureDetector(context, this);
        this.mViewMap              = new HashMap<>();
        this.mScaleGestureDetector = new ScaleGestureDetector(context, this);
        this.mScaling              = false;
        this.mWrapContent          = false;
        this.mDropOnScale          = false;
        // Register ourself as the OnTouchListener.
        this.setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(final View v, final MotionEvent event) {
        // Calculate the PointerId.
        final int lPointerId = event.getPointerId(event.getActionIndex());
        // Handle the TouchEvent.
        this.getGestureDetector().onTouchEvent(event);
        this.getScaleGestureDetector().onTouchEvent(event);
        // Did the user release a pointer?
        if(event.getAction() == MotionEvent.ACTION_UP) {
            // Was there a View associated with this Action?
            final View lView = this.getViewMap().get(lPointerId);
            // Does the View exist?
            if(lView != null) {
                // Remove the View from the Map.
                this.getViewMap().remove(lPointerId); /** TODO: Provide a Callback? */
            }
        }
        // Consume all events for now.
        return true;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        // Calculate the PointerId.
        final Integer lPointerId = Integer.valueOf(e.getPointerId(e.getActionIndex()));
        // Fetch the View.
        final View    lView      = this.getViewFor(Math.round(e.getRawX()), Math.round(e.getRawY()));
        // Is it valid?
        if(lView != null) {
            // Watch the View.
            this.getViewMap().put(lPointerId, lView);
            // Configure the Anchor.
            lView.setPivotX(0);
            lView.setPivotY(0);
            // Assert that we handled the event.
            return true;
        }
        // Assert that we ignored the event.
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        // Are we not scaling?
        if(!this.isScaling()) {
            // Calculate the PointerId.
            final Integer lPointerId = Integer.valueOf(e1.getPointerId(e1.getActionIndex()));
            // Fetch the View.
            final View    lView      = this.getViewMap().get(lPointerId);
            // Is the scroll valid for a given View?
            if(lView != null) {
                // Calculate the Scaled Width and Height of the View.
                final float lWidth    = lView.getWidth()  * lView.getScaleX();
                final float lHeight   = lView.getHeight() * lView.getScaleY();
                // Declare the initial position.
                final int[] lPosition = new int[] { (int)(e2.getX() - ((lWidth)  / 2)), (int)(e2.getY() - ((lHeight) / 2)) };
                // Are we wrapping content?
                if(this.isWrapContent()) {
                    // Wrap the Position.
                    this.onWrapContent(lPosition, lWidth, lHeight);
                }
                // Update the Drag.
                this.onUpdateDrag(lView, lPosition);
            }
            // Assert we handled the scroll.
            return true;
        }
        // Otherwise, don't permit scrolling. Don't consume the MotionEvent.
        return false;
    }

    /** Forces X/Y values to be coerced within the confines of the RegionView. */
    private final void onWrapContent(final int[] pPosition, final float pWidth, final float pHeight) {
        // Limit the parameters. (Top-Left)
        pPosition[0] = Math.max(pPosition[0], 0);
        pPosition[1] = Math.max(pPosition[1],  0);
        // Limit the parameters. (Bottom-Right)
        pPosition[0] = Math.min(pPosition[0], (int)(this.getWidth()  - pWidth));
        pPosition[1] = Math.min(pPosition[1], (int)(this.getHeight() - pHeight));
    }

    /** Updates the Drag Position of a child View within the Layout. Implicitly, we update the LayoutParams of the View. */
    private final void onUpdateDrag(final View pView, final int pLeft, final int pTop) {
        // Allocate some new MarginLayoutParams.
        final MarginLayoutParams lMarginLayoutParams = new MarginLayoutParams(pView.getLayoutParams());
        // Update the Margin.
        lMarginLayoutParams.setMargins(pLeft, pTop, 0, 0);
        // Refactor the MarginLayoutParams into equivalent LayoutParams for the RelativeLayout.
        pView.setLayoutParams(new RelativeLayout.LayoutParams(lMarginLayoutParams));
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        // Calculate the ScaleFactor.
              float lScaleFactor = detector.getScaleFactor() - 1;
        // Fetch the Scaled View.
        final View  lView        = this.getViewMap().entrySet().iterator().next().getValue();
        // Update the ScaleFactor.
        final float lScale       = this.getScale() + lScaleFactor;
        // Calculate the Proposed Width and Height.
        final int   lWidth  = Math.round(lView.getWidth()  * lScale);
        final int   lHeight = Math.round(lView.getHeight() * lScale);
        // Is the View already too large for wrap content?
        if(lWidth >= this.getWidth() || lHeight >= this.getHeight()) {
            // Don't update the scale.
            return false;
        }
        // Persist this Scale for the View.
        lView.setScaleX(lScale);
        lView.setScaleY(lScale);
        // Assign the Scale.
        this.setScale(lScale);
        // Compute the Position.
        final int[] lPosition = new int[] { Math.round(detector.getFocusX()) - (lWidth / 2), Math.round(detector.getFocusY()) - (lHeight / 2) };
        // Are we wrapping the Position?
        if(this.isWrapContent()) {
            // Wrap the Position.
            this.onWrapContent(lPosition, lWidth, lHeight);
        }
        // Update the Drag.
        this.onUpdateDrag(lView, lPosition);
        // Assert that we handled the scale.
        return true;
    }

    /** Update the Drag. */
    private final void onUpdateDrag(final View pView, final int[] pPosition) {
        // Call the sub-implementation.
        this.onUpdateDrag(pView, pPosition[0], pPosition[1]);
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) { 
        // Is the user not dragging at all?
        if(this.getViewMap().size() == 1) {
            // Fetch the View.
            final View lView = this.getViewMap().entrySet().iterator().next().getValue();
            // Initialize the Scale.
            this.setScale(lView.getScaleX()); 
            // Assert that we've started scaling.
            this.setScaling(true);
            // Inform the callback.
            return true;
        }
        // Otherwise, don't allow scaling.
        return false;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
        // Were we scaling?
        if(this.isScaling()) {
            // Assert that we've stopped scaling.
            this.setScaling(false);
            // Reset the Scale.
            this.setScale(Float.NaN);
            // Should we stop dragging now that we've finished scaling?
            if(this.isDropOnScale()) {
                // Clear the ViewMap.
                this.getViewMap().clear();
            }
        }
    }

    /** Returns the View colliding with the given co-ordinates. */
    private final View getViewFor(final int pX, final int pY) {
        // Declare the LocationBuffer.
        final int[] lLocationBuffer = new int[2];
        // Iterate the Views.
        for(int i = 0; i < this.getChildCount(); i++) {
            // Fetch the child View.
            final View lView = this.getChildAt(i);
            // Fetch its absolute position.
            lView.getLocationOnScreen(lLocationBuffer);
            // Determine if the MotionEvent collides with the View.
            if(pX > lLocationBuffer[0] && pY > lLocationBuffer[1] && (pX < lLocationBuffer[0] + (lView.getWidth() * lView.getScaleX())) && (pY < lLocationBuffer[1] + (lView.getHeight() * lView.getScaleY()))) {
                // Return the View.
                return lView;
            }
        }
        // We couldn't find a View.
        return null;
    }

    /* Unused Overrides. */
    @Override public void      onShowPress(MotionEvent e) {  }
    @Override public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }
    @Override public void      onLongPress(MotionEvent e) { }
    @Override public boolean       onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; }

    /* Getters and Setters. */
    private final GestureDetector getGestureDetector() {
        return this.mGestureDetector;
    }

    private final ScaleGestureDetector getScaleGestureDetector() {
        return this.mScaleGestureDetector;
    }

    private final Map<Integer, View> getViewMap() {
        return this.mViewMap;
    }

    private final void setScaling(final boolean pIsScaling) {
        this.mScaling = pIsScaling;
    }

    private final boolean isScaling() {
        return this.mScaling;
    }

    private final void setScale(final float pScale) {
        this.mScale = pScale;
    }

    private final float getScale() {
        return this.mScale;
    }

    /** Defines whether we coerce the drag and zoom of child Views within the confines of the Layout. */
    public final void setWrapContent(final boolean pIsWrapContent) {
        this.mWrapContent = pIsWrapContent;
    }

    public final boolean isWrapContent() {
        return this.mWrapContent;
    }

    /** Defines whether a drag operation is considered 'finished' once the user finishes scaling a view. */
    public final void setDropOnScale(final boolean pIsDropOnScale) {
        this.mDropOnScale = pIsDropOnScale;
    }

    public final boolean isDropOnScale() {
        return this.mDropOnScale;
    }

}

এখানে আমি ব্যবহারের একটি উদাহরণ দেখাই:

package com.zonal.regionview;

import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.AnalogClock;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Allocate a RegionView.
        final RegionView lRegionView = new RegionView(this);
        // Add some example items to drag.
        lRegionView.addView(new AnalogClock(this));
        lRegionView.addView(new AnalogClock(this));
        lRegionView.addView(new AnalogClock(this));
        // Assert that we only want to drag Views within the confines of the RegionView.
        lRegionView.setWrapContent(true);
        // Assert that after we've finished scaling a View, we want to stop being able to drag it until a new drag is started.
        lRegionView.setDropOnScale(true);
        // Look at the RegionView.
        this.setContentView(lRegionView);
    }

}

0

যেকোন ম্যানুয়ালি প্রবেশ করা সংখ্যার নির্ভরতা অপসারণ করতে @ ভাইচেস্লাভ শিলকিনের সরবরাহিত সমাধানটিকে কিছুটা পরিবর্তন করেছে।

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class MainActivity extends Activity implements View.OnTouchListener
{
    private int       _xDelta;
    private int       _yDelta;
    private int       _rightMargin;
    private int       _bottomMargin;
    private ImageView _floatingView;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this._floatingView = (ImageView) findViewById(R.id.textView);

        this._floatingView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
        {
            @Override
            public boolean onPreDraw()
            {
                if (_floatingView.getViewTreeObserver().isAlive())
                    _floatingView.getViewTreeObserver().removeOnPreDrawListener(this);

                updateLayoutParams(_floatingView);
                return false;
            }
        });

        this._floatingView.setOnTouchListener(this);
    }

    private void updateLayoutParams(View view)
    {
        this._rightMargin = -view.getMeasuredWidth();
        this._bottomMargin = -view.getMeasuredHeight();

        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(view.getMeasuredWidth(), view.getMeasuredHeight());
        layoutParams.bottomMargin = this._bottomMargin;
        layoutParams.rightMargin = this._rightMargin;

        view.setLayoutParams(layoutParams);
    }

    @Override
    public boolean onTouch(View view, MotionEvent event)
    {
        if (view == this._floatingView)
        {
            final int X = (int) event.getRawX();
            final int Y = (int) event.getRawY();

            switch (event.getAction() & MotionEvent.ACTION_MASK)
            {
                case MotionEvent.ACTION_DOWN:
                    RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    this._xDelta = X - lParams.leftMargin;
                    this._yDelta = Y - lParams.topMargin;
                    break;

                case MotionEvent.ACTION_MOVE:
                    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    layoutParams.leftMargin = X - this._xDelta;
                    layoutParams.topMargin = Y - this._yDelta;
                    layoutParams.rightMargin = this._rightMargin;
                    layoutParams.bottomMargin = this._bottomMargin;
                    view.setLayoutParams(layoutParams);
                    break;
            }

            return true;
        }
        else
        {
            return false;
        }
    }
}

0

এই উদাহরণে আপনি এর আকার, ত্রুটিবিহীন অ্যানিমেশন এবং ক্লিকগুলি ধরুন না কেন পিতামাতার সীমানার মধ্যে দৃশ্যটি সরিয়ে নিতে পারেন।

এই সমাধানটি অন্যান্য মন্তব্যের চেয়ে উচ্চতর হওয়ার কারণটি হল এই পদ্ধতির একটি নির্দেশিক প্যাড ব্যবহার করে যা নিজেই গণনা করে এবং ভিউ পজিশনে রিলে যায় না যা প্রচুর বাগের উত্স।

View view;
Animator.AnimatorListener listener;
boolean onMove = false;
boolean firstAnimation = true;
static final int CLICK_DURATION = 175;

float parentWidth;
float parentHeight;

// Those are the max bounds
// within the contianer
float xBoundMax;
float yBoundMax;

// This variables hold the target
// ordinates for the next
// animation in case an animation
// is already in progress.
float targetX;
float targetY;

float downRawX;
float downRawY;

public boolean onTouchEvent(MotionEvent event)
{
    switch (event.getAction())
    {
        case MotionEvent.ACTION_UP:
            if(event.getEventTime() - event.getDownTime() < CLICK_DURATION) click();
            onMove = false;
            break;
        case MotionEvent.ACTION_DOWN:
            firstAnimation = true;
            xBoundMax = parentWidth - view.getWidth();
            yBoundMax = parentHeight - view.getHeight();
            downRawX = event.getRawX();
            downRawY = event.getRawY();
            break;

        case MotionEvent.ACTION_MOVE:
            if(!onMove)
            {
                if(event.getEventTime() - event.getDownTime() < CLICK_DURATION) break;
                else onMove = true;
            }

            // Calculating the position the
            // view should be posed at.
            float offsetX = event.getRawX() - downRawX;
            float offsetY = event.getRawY() - downRawY;
            downRawX = event.getRawX();
            downRawY = event.getRawY();
            targetX = currentX + offsetX;
            targetY = currentY.getY() + offsetY;

            // Checking if view
            // is within parent bounds
            if(targetX > parentWidth - view.getWidth()) targetX = xBoundMax;
            else if (targetX < 0) targetX = 0;
            if(targetY > parentHeight - view.getHeight())targetY = yBoundMax;
            else if (targetY < 0) targetY = 0;

            // This check is becuase the user may just click on the view
            // So if it's a not a click, animate slowly but fastly
            // to the desired position
            if(firstAnimation)
            {
                firstAnimation = false;
                animate(70, getNewAnimationListener());
                break;
            }

            if(listener != null) break;
            animate(0, null);
            break;

            case MotionEvent.ACTION_BUTTON_PRESS:
        default:
            return false;
    }
    return true;
}

// Gets a new animation listener and reset
private android.animation.Animator.AnimatorListener getNewAnimationListener()
{
    listener =  new Animator.AnimatorListener() {
        @Override public void onAnimationStart(Animator animation) { }
        @Override public void onAnimationCancel(Animator animation) { }
        @Override public void onAnimationRepeat(Animator animation) { }
        @Override public void onAnimationEnd(Animator animation) {
            animation.removeListener(listener);
            listener = null;
            view.setAnimation(null);
            animate(0, null);
        }
    };
    return listener;
}

private void animate(int duration, @Nullable Animator.AnimatorListener listener)
{
    view.animate()
            .x(targetX)
            .y(targetY)
            .setDuration(duration)
            .setListener(listener)
            .start();
    currentX = targetX;
    currentY = targetY;
}

private void click()
{
    // Dohere stuff that you desire and than
}

যদি আপনার কাছে কোনও স্ক্রোলভিউ বা ডাবল ডাইমেনশন স্ক্রোলভিউয়ের মধ্যে ধারক থাকে তবে আপনার এই লাইনটি অন টিচটিতে যুক্ত করা উচিত

view.getParent().requestDisallowInterceptTouchEvent(true);

0

@ অ্যালেক্স কার্শিনের উত্তর হিসাবে একই , আমি কিছুটা পরিবর্তন করি।

public class MovingObject implements OnTouchListener {
private RelativeLayout.LayoutParams lParams;
private PointF viewPoint, prePoint, currPoint;

public MovingObject() {
    lParams = null;
    viewPoint = new PointF();
    prePoint = new PointF();
    currPoint = new PointF();
}

public boolean onTouch(View view, MotionEvent event) {
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        viewPoint.set(view.getX(), view.getY());
        prePoint.set(event.getRawX(), event.getRawY());
        lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
        break;
    case MotionEvent.ACTION_UP:
        break;
    case MotionEvent.ACTION_POINTER_DOWN:
        break;
    case MotionEvent.ACTION_POINTER_UP:
        break;
    case MotionEvent.ACTION_MOVE:
        currPoint.set(event.getRawX(), event.getRawY());
        moveToCurrentPoint(view);
        break;
    }
    view.invalidate();
    return true;
}

private void moveToCurrentPoint(View view) {
    float dx = currPoint.x - prePoint.x - prePoint.x + viewPoint.x;
    float dy = currPoint.y - prePoint.y - prePoint.y + viewPoint.y;
    lParams.leftMargin = (int) (prePoint.x + dx);
    lParams.topMargin = (int) (prePoint.y + dy);
    view.setLayoutParams(lParams);
}
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.