您的位置:首页 > 移动开发 > IOS开发

仿ios短信列表滑动出现删除按钮

2016-06-07 19:52 423 查看
最近还没找到工作所以在宿舍有点闲,所以呢就自己写了这么一个例子。之前网上有很多人写过类似的文章或demo,github上面也有开源项目。但是,老是copy别人代码也怪没意思的,于是就自己尝试着自己写呗。废话多了先来看下效果咯:

运行效果:



1、实现思路

其实实现思路很简单那就是在ListView的item里面放一个可以滑动的view,这里我用的是HorizontalScrollView。我之所以选HorizontalScrollView是因为可以不用去处理move事件

2、SildingView的实现

SildingView是我自定义的一个View 他继承的是HorizontalScrollView,SildingView就是我们要放到ListView item里面的View。代码如下所示:

SlideView.java

package okhttp.lc.com.lateralslidingitem;

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.Scroller;

/**
* Created by HP on 2016/6/6.
*/
public class SildingView extends HorizontalScrollView {
int mScreenWidth;
boolean once = false;
//将MenuItem的宽度设置为100px
int MenuWidth = 100;
LinearLayout wapperView;
LinearLayout mContent;
LinearLayout mMenu;

OpenStatusListener mListener;

//判断菜单是否打开
boolean isOpen = false;

public SildingView(Context context) {
this(context, null);
}

public SildingView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public SildingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

public void setContent(View view) {
addView(view);
}

private void init(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
}

/**
* 设置ItemMenu打开监听事件
* @param mListener
*/
public void setOpenStatusListener(OpenStatusListener mListener) {
this.mListener = mListener;
}

public interface OpenStatusListener {
//status 0表示打开 1表示关闭
void getOpenStatus(int status);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP: {
if (getScrollX() >= MenuWidth / 2) {
smoothScrollTo(MenuWidth, 0);
isOpen = true;
mListener.getOpenStatus(0);
} else {
smoothScrollTo(0, 0);
isOpen = false;
mListener.getOpenStatus(1);
}
}
return true;
}
return super.onTouchEvent(ev);
}

/**
* 打开ItemMenu
*/
public void openItemMenu() {
if (!isOpen) {
smoothScrollTo(MenuWidth, 0);
isOpen = true;
mListener.getOpenStatus(0);
}
}

public boolean getStatus() {
return isOpen;
}

/**
* 关闭ItemMenu
*/
public void closeItemMenu() {
if (isOpen) {
smoothScrollTo(0, 0);
isOpen = false;
mListener.getOpenStatus(1);
}
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//onMeasure会多次调用,用once来控制以防多次执行以下代码
if (!once) {
wapperView = (LinearLayout) getChildAt(0);
mContent = (LinearLayout) wapperView.getChildAt(0);
mMenu = (LinearLayout) wapperView.getChildAt(1);
mContent.getLayoutParams().width = mScreenWidth;
mMenu.getLayoutParams().width = MenuWidth;
once = true;
}
}

}


3、Activity的实现

package okhttp.lc.com.lateralslidingitem;

import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

ListView lv_main;
List<String> list = new ArrayList<String>();
okhttp.lc.com.lateralslidingitem.SildingView mSlidingView;

MyAdapter adapter;
boolean isOpen = false;

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

private void initData() {
for (int i = 0; i < 40; i++) {
list.add("SomeThing" + (i + 1));
}
adapter = new MyAdapter(this);
lv_main.setAdapter(adapter);
/**
* 监听ListView的滑动
*/
lv_main.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int action = motionEvent.getAction();
if (check()) {
Log.e("TAG", "true");
switch (action) {
case MotionEvent.ACTION_DOWN: {
close();
}
break;
case MotionEvent.ACTION_MOVE: {
close();
}
break;
case MotionEvent.ACTION_UP: {
close();
}
break;
}
return true;
}
return false;
}
});
}

/**
* 关闭ItemMenu
*/
private void close() {
Log.e("TAG", "close");
for (int i = 0; i < lv_main.getChildCount(); i++) {
SildingView v = (SildingView) lv_main.getChildAt(i);
v.closeItemMenu();
}
}

/**
* 检查是否有打开的ItemMenu
* @return
*/
private boolean check() {
for (int i = 0; i < lv_main.getChildCount(); i++) {
SildingView v2 = (SildingView) lv_main.getChildAt(i);
if (v2.getStatus()) {
isOpen = true;
return isOpen;
}
}
return false;
}

private void initViews() {
lv_main = (ListView) findViewById(R.id.lv_main);
}

class MyAdapter extends BaseAdapter implements SildingView.OpenStatusListener {
private LayoutInflater mInflater;
private Context mContext;

MyAdapter(Context mContext) {
this.mContext = mContext;
mInflater = LayoutInflater.from(mContext);
}

@Override
public int getCount() {
return list.size();
}

@Override
public Object getItem(int i) {
return list.get(i);
}

@Override
public long getItemId(int i) {
return i;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder mViewHolder = null;
mSlidingView = (SildingView) view;
if (mSlidingView == null) {
mViewHolder = new ViewHolder();
View itemview = mInflater.inflate(R.layout.item, null);
mSlidingView = new SildingView(MainActivity.this);
/**
* 貌似HorizontalScrollView的click事件被屏蔽了,应此为了实现点击效果采用了这种方法。
*/
final LinearLayout ll_item = (LinearLayout) itemview.findViewById(R.id.ll_item);
final int in=i;
ll_item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (check()) {
close();
} else
Toast.makeText(getApplicationContext(), "click" + in, Toast.LENGTH_SHORT).show();
}
});
mSlidingView.setContent(itemview);
mSlidingView.setOpenStatusListener(this);
mViewHolder.textView = (TextView) mSlidingView.findViewById(R.id.textView);
mViewHolder.delete = (TextView) mSlidingView.findViewById(R.id.delete);
mSlidingView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) mSlidingView.getTag();

}
mViewHolder.textView.setText(getItem(i).toString());
mViewHolder.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(), "delete", Toast.LENGTH_LONG).show();
}
});
return mSlidingView;
}

@Override
public void getOpenStatus(int status) {
if (status == 0) {
Toast.makeText(getApplicationContext(), "打开", Toast.LENGTH_SHORT).show();
//                isOpen = true;
} else {
Toast.makeText(getApplicationContext(), "关闭" , Toast.LENGTH_SHORT).show();
//                isOpen = false;
}
}
}

class ViewHolder {
TextView textView;
TextView delete;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();

//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, Activity2.class);
startActivity(intent);
return true;
}

return super.onOptionsItemSelected(item);
}
}


同样也是将MainActivity的代码全部贴出来,为了方便我写了一个静态内部的Adapter。在getView()方法中将第三个参数强制转化为SildingView,然后定义一个item_view来获取加载好的布局文件,再将item_view做为SildingView的内容添加进去,最后返回SildingView。这样就很好的实现了将SildingView做为ListView的item添加进去,呃描述的实在不好能力有限啊还是看代码理解吧。。。。

如果仔细一点会发现iphone手机短信列表,如果有一个item的ItemMenu处于打开状态那么接下来无论用户是滑动列表还是点击列表的item都将没有应有的效果,而产生的效果就是将打开的ItemMenu关闭。为了实现这个效果我重写了ListView的onTouch()方法,在move事件中通过遍历ListView的所有item来检查是否有item的ItemMenu已经打开如果有则将其关闭并且屏蔽掉onTouchEvent()方法使得ListView无法滑动。最后一个问题就是item的点击事件的问题,因为我们将View换成了SlidingView(SlidingView是一个HorizontalScrollView,而HorizontalScrollView貌似将click事件屏蔽掉了)导致我们给ListView设置onItemClick事件失效,因此我选择在getView()方法中设置SlidingView中的子View的click事件这样同样实现了ListView的调集效果。但是这绝对不是最好的方法

4、布局文件

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

</RelativeLayout>


item.xml

<?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:descendantFocusability="blocksDescendants"
android:id="@+id/ll_item"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/ll_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#50000000"
>
<TextView
android:id="@+id/delete"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="delete"
android:gravity="center"
/>
</LinearLayout>
</LinearLayout>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: