这个简易 的底部拖拉菜单没什么工作量,这里氷分析了,直接上代码,距离属性没剥离出来,不过很简单,各位大神用到的时候,自己扩展吧
代码如下:
@interface ViewController ()
@property(nonatomic,strong) UIView* bottomView;
@property(nonatomic, strong) NSLayoutConstraint *bottomHeightCons;
@property(nonatomic,assign) CGPoint startPos;
@property(nonatomic,assign) CGPoint endPos;
@property(nonatomic,assign) CGPoint originPos;
@property(nonatomic,assign) BOOL bIsDirectionDowm;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initView];
}
-(void) initView{
self.bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 100,
self.view.frame.size.width, 300)];
self.bottomView.backgroundColor = [UIColor greenColor];
self.bottomView.translatesAutoresizingMaskIntoConstraints = NO;
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(100, self.bottomView.frame.size.height - 80, 160, 40)];
label.text = @"底部隐藏菜单";
[self.bottomView addSubview:label];
[self.view addSubview:self.bottomView];
self.originPos = self.bottomView.center;
self.bIsDirectionDowm = false;
}
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
self.startPos = [touch locationInView:self.view];
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint curP = [touch locationInView:self.view];
if(curP.y - self.startPos.y <= 0 && curP.y - self.startPos.y >= -200){ //向上滑
if(self.bIsDirectionDowm) return;
self.bottomView.center = CGPointMake(self.bottomView.center.x, self.originPos.y + ( curP.y - self.startPos.y));
}else if(curP.y - self.startPos.y > 0 && curP.y - self.startPos.y <= 100){ //向下滑动
if(!self.bIsDirectionDowm) return;
self.bottomView.center = CGPointMake(self.bottomView.center.x, self.originPos.y - 100 + ( curP.y - self.startPos.y));
}
}
//当手指离开屏幕时调用
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
self.endPos = [touch locationInView:self.view];
if(self.endPos.y - self.startPos.y <= 0 && self.endPos.y - self.startPos.y >= -100){ //向上滑动
[UIView animateWithDuration:0.3 animations:^{
self.bottomView.center = CGPointMake(self.bottomView.center.x, self.view.frame.size.height - self.bottomView.frame.size.height / 2);
self.bIsDirectionDowm = true;
}];
}
else if(self.endPos.y - self.startPos.y >= 0 && self.endPos.y - self.startPos.y <= 100){
[UIView animateWithDuration:0.1 animations:^{
self.bottomView.center = CGPointMake(self.bottomView.center.x, self.originPos.y);
self.bIsDirectionDowm = false;
}];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
Android 部分:参考:https://www.jb51.net/article/117780.htm
package com.sensetime.armap.widgt;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Scroller;
import androidx.annotation.Nullable;
import com.sensetime.armap.R;
import com.sensetime.libcenter.utils.LogUtils;
/**
* Create By 刘铁柱
* Create Date 2019-09-11
* Sensetime@Copyright
* Des: 垂直可伸缩菜单
*/
public class ElasticLayout extends LinearLayout {
LinearLayout bottomBar,bottomContent;
private Scroller mScroller;
public ElasticLayout(Context context) {
super(context);
}
public ElasticLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
public ElasticLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScroller = new Scroller(context);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
bottomContent = findViewById(R.id.bottomContent);
bottomBar = findViewById(R.id.bottombar);
findViewById(R.id.bottom_btn).setOnClickListener(new OnClickListener(){
@Override
public void onClick(View view) {
LogUtils.print(48,"");
}
});
findViewById(R.id.bottom_btn2).setOnClickListener(new OnClickListener(){
@Override
public void onClick(View view) {
LogUtils.print(56,"");
}
});
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
bottomBar.layout(0, getMeasuredHeight() - bottomBar.getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight());
bottomContent.layout(0, getMeasuredHeight(), getMeasuredWidth(), bottomBar.getBottom() + bottomContent.getMeasuredHeight());
}
float downX,downY;
int scrollOffset;
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
downX = (int) event.getX();
downY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
int endY = (int) event.getY();
int dy = (int) (endY - downY);
int toScroll = getScrollY() - dy;
if(toScroll < 0){
toScroll = 0;
} else if(toScroll > bottomContent.getMeasuredHeight()){
toScroll = bottomContent.getMeasuredHeight();
}
scrollTo(0, toScroll);
downY = (int) event.getY();
break;
case MotionEvent.ACTION_UP:
scrollOffset = getScrollY();
if(scrollOffset > bottomContent.getMeasuredHeight() / 2){
expendBottom();
} else {
closeBottom();
}
break;
}
return true;
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) { // 计算新位置,并判断上一个滚动是否完成。
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();// 再次调用computeScroll。
}
}
private void expendBottom(){
int dy = bottomContent.getMeasuredHeight() - scrollOffset;
mScroller.startScroll(getScrollX(), getScrollY(), 0, dy, 500);
invalidate();
}
private void closeBottom(){
int dy = 0 - scrollOffset;
mScroller.startScroll(getScrollX(), getScrollY(), 0, dy, 500);
invalidate();
}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.sensetime.armap.widgt.ElasticLayout
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/bottombar"
android:orientation="vertical"
android:background="@color/colorAccent"
android:layout_width="match_parent"
android:layout_height="50dp">
<Button
android:id="@+id/bottom_btn"
android:text="test_click"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/bottomContent"
android:orientation="vertical"
android:background="@color/colorPrimaryDark"
android:layout_width="match_parent"
android:layout_height="200dp">
<Button
android:id="@+id/bottom_btn2"
android:text="test_click2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</com.sensetime.armap.widgt.ElasticLayout>
</LinearLayout>