Skip to content

Commit

Permalink
优化性能,修复打开周边出现瞬间滑动位置不对问题
Browse files Browse the repository at this point in the history
  • Loading branch information
Mosect committed May 24, 2019
1 parent f0cb2d1 commit 9ec7181
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 40 deletions.
1 change: 1 addition & 0 deletions example/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
android:allowBackup="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ public void onClick(View v) {
Toast.makeText(btnRight.getContext(), "点击了右边按钮", Toast.LENGTH_SHORT).show();
}
});

// 将right和btnRight的宽度设置成一样
dragLayout.postAfterLayout(new Runnable() {
@Override
public void run() {
ViewGroup.LayoutParams lp = right.getLayoutParams();
lp.width = btnRight.getWidth();
right.setLayoutParams(lp);
}
});
return holder;
}

Expand Down
20 changes: 11 additions & 9 deletions example/src/main/res/layout/item_list2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ly_drag"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="70dp"
android:background="#303030"
app:overScroll="left">

Expand All @@ -17,32 +17,34 @@
android:minHeight="0dp"
android:paddingLeft="25dp"
android:paddingRight="25dp"
android:stateListAnimator="@null"
android:text="左边的按钮"
android:textColor="#0080ff"
app:layout_layer="left" />

<FrameLayout
android:id="@+id/ly_right"
android:layout_width="120dp"
android:layout_height="match_parent"
app:layout_layer="right" />

<Button
android:id="@+id/btn_right"
android:layout_width="wrap_content"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:background="@android:color/transparent"
android:minWidth="0dp"
android:minHeight="0dp"
android:paddingLeft="25dp"
android:paddingRight="25dp"
android:stateListAnimator="@null"
android:text="右边的按钮"
android:textColor="#0080ff" />

<FrameLayout
android:id="@+id/ly_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:layout_layer="right" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:background="#ffffff"
android:clickable="true"
android:focusable="true"
Expand Down
2 changes: 1 addition & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ publish {
userOrg = 'mosect' // bintray.com用户名
groupId = 'com.mosect' // jcenter上的路径,bintray上创建Package时填写的Version control项
artifactId = 'DragLayout' // 项目名称,bintray上创建Package时填写的Name项
publishVersion = '1.0.2' // 版本号
publishVersion = '1.0.3-beta' // 版本号
desc = 'Android拖拽控件' // 描述,不重要
website = 'http://www.mosect.com' // 网站,最好有,不重要
}
Expand Down
134 changes: 114 additions & 20 deletions library/src/main/java/com/mosect/draglayout/lib/DragLayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
import android.widget.Scroller;

import com.mosect.viewutils.GestureHelper;
import com.mosect.viewutils.MeasureUtils;

import java.util.LinkedList;

public class DragLayout extends FrameLayout {
public class DragLayout extends ViewGroup {

/**
* 默认滑动速度,dip/秒
Expand Down Expand Up @@ -72,10 +73,11 @@ public class DragLayout extends FrameLayout {
private VelocityTracker velocityTracker; // 速度辅助工具
private int touchScrollStartX; // 开始触摸时滑动层的滑动位置X
private int touchScrollStartY; // 开始触摸时滑动层的滑动位置Y
private float touchStartX;
private float touchStartY;
private boolean touching;
private float touchStartX; // 开始触摸滑动位置:X
private float touchStartY; // 开始触摸滑动位置:Y
private boolean touching; // 是否正在滑动中
private Scroller layerScroller; // 滑动层的滑动器
private long viewInfoCode = 0; // 视图信息hash code,如果视图发生变化,此hashCode会发生改变

private OnLayerScrollChangedListener onLayerScrollChangedListener;
private CanOpenEdgeCallback canOpenEdgeCallback;
Expand Down Expand Up @@ -124,12 +126,12 @@ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp)
}

@Override
protected FrameLayout.LayoutParams generateDefaultLayoutParams() {
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}

@Override
public FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}

Expand Down Expand Up @@ -358,8 +360,56 @@ private void resetTouchStart(float x, float y) {

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 使用FrameLayout的方法测量子视图大小和本身大小
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
long code = computeInfoCode((long) widthMeasureSpec + heightMeasureSpec);
if (code == viewInfoCode) {
// 视图没有发生更改,不需要再次测量,直接使用旧的宽和高
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
return;
}
viewInfoCode = code;

// 获取内间距
int paddingWidth = getPaddingLeft() + getPaddingRight();
int paddingHeight = getPaddingTop() + getPaddingBottom();
// 制作自己的测量规格,用于约束子视图
int smsw = MeasureUtils.makeSelfMeasureSpec(widthMeasureSpec, paddingWidth);
int smsh = MeasureUtils.makeSelfMeasureSpec(heightMeasureSpec, paddingHeight);
// 内容的大小
int contentWidth = 0;
int contentHeight = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) continue;

LayoutParams lp = (LayoutParams) child.getLayoutParams();
// 获取外边距
int marginWidth = lp.leftMargin + lp.rightMargin;
int marginHeight = lp.topMargin + lp.bottomMargin;
// 制作子视图的测量规格
int cmsw = MeasureUtils.makeChildMeasureSpec(smsw, lp.width, marginWidth);
int cmsh = MeasureUtils.makeChildMeasureSpec(smsh, lp.height, marginHeight);
// 测量子视图
child.measure(cmsw, cmsh);
// 子视图实际占用的大小(包括外边距)
int cw = marginWidth + child.getMeasuredWidth();
int ch = marginHeight + child.getMeasuredHeight();
// 选最大的作为内容大小
if (cw > contentWidth) {
contentWidth = cw;
}
if (ch > contentHeight) {
contentHeight = ch;
}
}
// 最后的内容大小应该加上内边距
contentWidth += paddingWidth;
contentHeight += paddingHeight;
// 获取当前内容大小对应的视图大小
int width = MeasureUtils.getMeasuredDimension(contentWidth, widthMeasureSpec);
int height = MeasureUtils.getMeasuredDimension(contentHeight, heightMeasureSpec);
// 设置视图大小
setMeasuredDimension(width, height);

edgeSize.setEmpty(); // 清空边缘大小
centerRect.left = getPaddingLeft();
centerRect.top = getPaddingTop();
Expand Down Expand Up @@ -420,14 +470,15 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
*/
protected void onLayoutChildren() {
// 布局子View
System.out.println("onLayoutChildren==================");
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) continue;

LayoutParams lp = (LayoutParams) child.getLayoutParams();
int gravity = lp.gravity;
// 默认放在左上角
if (gravity == Gravity.NO_GRAVITY || gravity == LayoutParams.UNSPECIFIED_GRAVITY)
if (gravity == Gravity.NO_GRAVITY)
gravity = Gravity.LEFT | Gravity.TOP;
// 计算子视图占用的空间
int widthSpace = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
Expand Down Expand Up @@ -469,8 +520,9 @@ protected void onLayoutChildren() {
break;
}

// 更具重力倾向,计算出视图位置
// 根据重力倾向,计算出视图位置
Gravity.apply(gravity, widthSpace, heightSpace, containerRect, outRect);
System.out.println(String.format("Gravity.apply:%s,%s", containerRect, outRect));
outRect.left += lp.leftMargin;
outRect.top += lp.topMargin;
outRect.right -= lp.rightMargin;
Expand Down Expand Up @@ -515,9 +567,7 @@ public void layerScrollTo(int x, int y) {
this.layerScrollY = y;
// System.out.println(String.format("layerScrollTo:x=%d,y=%d", x, y));
// 重新布局
onLayoutChildren();

// 更改周边状态
requestLayout();

// 触发对应方法
onLayerScrollChanged(oldX, oldY, x, y);
Expand Down Expand Up @@ -654,6 +704,7 @@ public boolean canScrollVertically(int direction) {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
System.out.println("DragLayout:onDetachedFromWindow");
viewInfoCode = 0;
afterLayout = false;
afterLayoutRunnableList = null;
}
Expand Down Expand Up @@ -810,6 +861,36 @@ protected boolean canVerticalScrollTo(int y) {
return true;
}

/**
* 计算视图信息hash code
*
* @param offset 开始计算的偏移量
* @return hash code
*/
protected long computeInfoCode(long offset) {
int count = getChildCount();
long result = offset;
int index = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
result = computeHash(result, child.getVisibility(), index++);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
result = computeHash(result, lp.layer, index++);
result = computeHash(result, lp.gravity, index++);
result = computeHash(result, lp.width, index++);
result = computeHash(result, lp.height, index++);
result = computeHash(result, lp.leftMargin, index++);
result = computeHash(result, lp.topMargin, index++);
result = computeHash(result, lp.rightMargin, index++);
result = computeHash(result, lp.bottomMargin, index++);
}
return result;
}

private long computeHash(long start, long value, long index) {
return start + (value << (index % 32));
}

/**
* 获取左边大小
*
Expand Down Expand Up @@ -964,6 +1045,9 @@ public void run() {
if (smooth) {
smoothLayerScrollTo(getHorizontalLayerScrollMin(), 0);
} else {
if (!layerScroller.isFinished()) {
layerScroller.abortAnimation();
}
layerScrollTo(getHorizontalLayerScrollMin(), 0);
}
}
Expand All @@ -982,6 +1066,9 @@ public void run() {
if (smooth) {
smoothLayerScrollTo(0, getVerticalLayerScrollMin());
} else {
if (!layerScroller.isFinished()) {
layerScroller.abortAnimation();
}
layerScrollTo(0, getVerticalLayerScrollMin());
}
}
Expand All @@ -1000,6 +1087,9 @@ public void run() {
if (smooth) {
smoothLayerScrollTo(getHorizontalLayerScrollMax(), 0);
} else {
if (!layerScroller.isFinished()) {
layerScroller.abortAnimation();
}
layerScrollTo(getHorizontalLayerScrollMax(), 0);
}
}
Expand All @@ -1018,6 +1108,9 @@ public void run() {
if (smooth) {
smoothLayerScrollTo(0, getVerticalLayerScrollMax());
} else {
if (!layerScroller.isFinished()) {
layerScroller.abortAnimation();
}
layerScrollTo(0, getVerticalLayerScrollMax());
}
}
Expand All @@ -1036,6 +1129,9 @@ public void run() {
if (smooth) {
smoothLayerScrollTo(0, 0);
} else {
if (!layerScroller.isFinished()) {
layerScroller.abortAnimation();
}
layerScrollTo(0, 0);
}
}
Expand Down Expand Up @@ -1089,10 +1185,10 @@ public void setMaxScrollTime(int maxScrollTime) {
this.maxScrollTime = maxScrollTime;
}

public static class LayoutParams extends FrameLayout.LayoutParams {
public static class LayoutParams extends MarginLayoutParams {

/**
* 层:无,表示放置在布局中间不滑动层
* 层:无,不受滑动影响,效果相当于将视图放在FrameLayout中
*/
public static final int LAYER_NONE = 0;
/**
Expand All @@ -1117,25 +1213,23 @@ public static class LayoutParams extends FrameLayout.LayoutParams {
public static final int LAYER_BOTTOM = 5;

/**
*
* 表示视图位于的层
*/
public int layer = LAYER_NONE;
public int gravity;

public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray ta = c.obtainStyledAttributes(attrs, R.styleable.DragLayout_Layout);
this.layer = ta.getInt(R.styleable.DragLayout_Layout_layout_layer, LAYER_NONE);
this.gravity = ta.getInt(R.styleable.DragLayout_Layout_android_layout_gravity, Gravity.NO_GRAVITY);
ta.recycle();
}

public LayoutParams(int width, int height) {
super(width, height);
}

public LayoutParams(int width, int height, int gravity) {
super(width, height, gravity);
}

public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
Expand Down
1 change: 1 addition & 0 deletions library/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
<enum name="right" value="4" />
<enum name="bottom" value="5" />
</attr>
<attr name="android:layout_gravity" />
</declare-styleable>
</resources>

0 comments on commit 9ec7181

Please sign in to comment.