Last active
August 8, 2019 09:37
-
-
Save deyanm/58cbd80cd9907cf520c7a06b567eefba to your computer and use it in GitHub Desktop.
Dragging panel with ViewDragHelper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@android:color/white"> | |
<Button | |
android:id="@+id/hidden_button" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:text="Hidden button" | |
android:textSize="64sp" /> | |
<TextView | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:text="Some text" | |
android:layout_below="@id/hidden_button" | |
android:padding="10dp" | |
android:textSize="20sp"/> | |
<com.whiterabbit.dragqueen.DraggingPanel | |
android:id="@+id/outer_layout" | |
android:layout_width="match_parent" | |
android:layout_height="350dp" | |
android:layout_alignParentBottom="true"> | |
<LinearLayout | |
android:id="@+id/main_layout" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:clickable="true" | |
android:background="#1E90FF" | |
android:orientation="vertical"> | |
<LinearLayout | |
android:id="@+id/queen_button" | |
android:layout_width="match_parent" | |
android:layout_height="50dp" | |
android:layout_marginTop="10dp" | |
android:orientation="horizontal" | |
android:weightSum="3"> | |
<EditText | |
android:id="@+id/resolverComentar" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginStart="5dp" | |
android:layout_weight="2.5" | |
android:ems="10" | |
android:inputType="textMultiLine" | |
android:padding="10dp" | |
android:scrollbars="vertical" /> | |
<Button | |
android:id="@+id/sendMessage" | |
android:layout_width="50dp" | |
android:layout_height="50dp" | |
android:layout_gravity="center" | |
android:layout_marginEnd="5dp" | |
android:layout_weight="0.5" | |
android:background="@android:drawable/ic_menu_send" | |
android:enabled="false" | |
android:textSize="16sp" | |
android:textStyle="bold" /> | |
</LinearLayout> | |
<LinearLayout | |
android:id="@+id/buttonsLayout" | |
android:layout_width="match_parent" | |
android:layout_height="60dp" | |
android:background="?android:colorBackground" | |
android:orientation="horizontal" | |
android:weightSum="2"> | |
<Button | |
android:id="@+id/button1" | |
android:layout_width="wrap_content" | |
android:layout_height="match_parent" | |
android:layout_margin="5dp" | |
android:layout_weight="1" | |
android:gravity="center" | |
android:background="#ADFF2F" | |
android:text="Accept" | |
android:textAllCaps="false" | |
android:textSize="20sp" /> | |
<Button | |
android:id="@+id/button2" | |
android:layout_width="wrap_content" | |
android:layout_height="match_parent" | |
android:layout_margin="5dp" | |
android:layout_weight="1" | |
android:gravity="center" | |
android:padding="10dp" | |
android:text="Decline" | |
android:background="#FF4500" | |
android:textAllCaps="false" | |
android:textSize="20sp" /> | |
</LinearLayout> | |
<WebView | |
android:id="@+id/webview" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> | |
</LinearLayout> | |
</com.whiterabbit.dragqueen.DraggingPanel> | |
</RelativeLayout> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.whiterabbit.dragqueen" > | |
<uses-permission android:name="android.permission.INTERNET"/> | |
<application | |
android:allowBackup="true" | |
android:icon="@drawable/ic_launcher" | |
android:label="@string/app_name" | |
android:theme="@style/AppTheme" > | |
<activity | |
android:name=".MainActivity" | |
android:label="@string/app_name" | |
android:windowSoftInputMode="adjustPan"> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
</application> | |
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.support.v4.view.ViewCompat; | |
import android.support.v4.widget.ViewDragHelper; | |
import android.util.AttributeSet; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.widget.LinearLayout; | |
import android.widget.RelativeLayout; | |
public class DraggingPanel extends RelativeLayout { | |
private final double AUTO_OPEN_SPEED_LIMIT = 800.0; | |
private int mDraggingState = 0; | |
private LinearLayout mQueenButton; | |
private ViewDragHelper mDragHelper; | |
private int mDraggingBorder; | |
private int mVerticalRange; | |
private boolean mIsOpen; | |
public class DragHelperCallback extends ViewDragHelper.Callback { | |
@Override | |
public void onViewDragStateChanged(int state) { | |
if (state == mDraggingState) { // no change | |
return; | |
} | |
if ((mDraggingState == ViewDragHelper.STATE_DRAGGING || mDraggingState == ViewDragHelper.STATE_SETTLING) && | |
state == ViewDragHelper.STATE_IDLE) { | |
// the view stopped from moving. | |
if (mDraggingBorder == 0) { | |
onStopDraggingToClosed(); | |
} else if (mDraggingBorder == mVerticalRange) { | |
mIsOpen = true; | |
} | |
} | |
if (state == ViewDragHelper.STATE_DRAGGING) { | |
onStartDragging(); | |
} | |
mDraggingState = state; | |
} | |
@Override | |
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { | |
mDraggingBorder = top; | |
} | |
public int getViewVerticalDragRange(View child) { | |
return mVerticalRange; | |
} | |
@Override | |
public boolean tryCaptureView(View view, int i) { | |
return (view.getId() == R.id.main_layout); | |
} | |
@Override | |
public int clampViewPositionVertical(View child, int top, int dy) { | |
final int topBound = getPaddingTop(); | |
final int bottomBound = mVerticalRange; | |
return Math.min(Math.max(top, topBound), bottomBound); | |
} | |
@Override | |
public void onViewReleased(View releasedChild, float xvel, float yvel) { | |
final float rangeToCheck = mVerticalRange; | |
if (mDraggingBorder == 0) { | |
mIsOpen = false; | |
return; | |
} | |
if (mDraggingBorder == rangeToCheck) { | |
mIsOpen = true; | |
return; | |
} | |
boolean settleToOpen = false; | |
if (yvel > AUTO_OPEN_SPEED_LIMIT) { // speed has priority over position | |
settleToOpen = true; | |
} else if (yvel < -AUTO_OPEN_SPEED_LIMIT) { | |
settleToOpen = false; | |
} else if (mDraggingBorder > rangeToCheck / 2) { | |
settleToOpen = true; | |
} else if (mDraggingBorder < rangeToCheck / 2) { | |
settleToOpen = false; | |
} | |
final int settleDestY = settleToOpen ? mVerticalRange : 0; | |
if(mDragHelper.settleCapturedViewAt(0, settleDestY)) { | |
ViewCompat.postInvalidateOnAnimation(DraggingPanel.this); | |
} | |
} | |
} | |
public DraggingPanel(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
mIsOpen = false; | |
} | |
@Override | |
protected void onFinishInflate() { | |
mQueenButton = findViewById(R.id.queen_button); | |
mDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback()); | |
mIsOpen = false; | |
super.onFinishInflate(); | |
} | |
@Override | |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
mVerticalRange = (int) (h * 0.84); | |
super.onSizeChanged(w, h, oldw, oldh); | |
} | |
private void onStopDraggingToClosed() { | |
// To be implemented | |
} | |
private void onStartDragging() { | |
} | |
private boolean isQueenTarget(MotionEvent event) { | |
int[] queenLocation = new int[2]; | |
mQueenButton.getLocationOnScreen(queenLocation); | |
int upperLimit = queenLocation[1] + mQueenButton.getMeasuredHeight(); | |
int lowerLimit = queenLocation[1]; | |
int y = (int) event.getRawY(); | |
return (y > lowerLimit && y < upperLimit); | |
} | |
@Override | |
public boolean onInterceptTouchEvent(MotionEvent event) { | |
if (isQueenTarget(event) && mDragHelper.shouldInterceptTouchEvent(event)) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
if (isQueenTarget(event) || isMoving()) { | |
mDragHelper.processTouchEvent(event); | |
return true; | |
} else { | |
return super.onTouchEvent(event); | |
} | |
} | |
@Override | |
public void computeScroll() { // needed for automatic settling. | |
if (mDragHelper.continueSettling(true)) { | |
ViewCompat.postInvalidateOnAnimation(this); | |
} | |
} | |
public boolean isMoving() { | |
return (mDraggingState == ViewDragHelper.STATE_DRAGGING || | |
mDraggingState == ViewDragHelper.STATE_SETTLING); | |
} | |
public boolean isOpen() { | |
return mIsOpen; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Activity; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.LinearLayout; | |
import android.widget.Toast; | |
public class MainActivity extends Activity implements View.OnClickListener { | |
private LinearLayout mQueen; | |
private Button mHidden, accept, decline; | |
private OuterLayout mOuterLayout; | |
private LinearLayout mMainLayout; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
mOuterLayout = findViewById(R.id.outer_layout); | |
mMainLayout = findViewById(R.id.main_layout); | |
mHidden = findViewById(R.id.hidden_button); | |
accept = findViewById(R.id.button1); | |
accept.setOnClickListener(this); | |
decline = findViewById(R.id.button2); | |
decline.setOnClickListener(this); | |
mHidden.setOnClickListener(this); | |
mQueen = findViewById(R.id.queen_button); | |
mQueen.setOnClickListener(this); | |
mMainLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { | |
@Override | |
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { | |
if (mOuterLayout.isMoving()) { | |
v.setTop(oldTop); | |
v.setBottom(oldBottom); | |
v.setLeft(oldLeft); | |
v.setRight(oldRight); | |
} | |
} | |
}); | |
} | |
@Override | |
public void onClick(View v) { | |
Button b = (Button) v; | |
Toast t = Toast.makeText(this, b.getText() + " clicked", Toast.LENGTH_SHORT); | |
t.show(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment