Android 自定义ListView Item侧滑删除
本程序是基于网上开源项目修改而来,具体来源忘了,懒得搜了,如果有不合适的地方,请原作者联系我,我会及时回复和处理的!
该例子程序中主要包含两个ListView,一个是实现侧滑删除,一个是侧滑出菜单,代码中的注释很全,我就不在赘述了,直接贴上核心代码和效果图。
侧滑删除ListView:
002.
package
com.example.testslidelistview;
003.
import
android.content.Context;
004.
import
android.util.AttributeSet;
005.
import
android.view.MotionEvent;
006.
import
android.view.VelocityTracker;
007.
import
android.view.View;
008.
import
android.view.ViewConfiguration;
009.
import
android.view.WindowManager;
010.
import
android.widget.AdapterView;
011.
import
android.widget.ListView;
012.
import
android.widget.Scroller;
013.
014.
/**
015.
*
侧滑删除Item的ListView,此处是对网上开源的一个Listview的完善,
016.
*
实现在手指滑动时item的透明度随之改变,并增加回到原位置的动画过程
017.
*
@author zhangshuo
018.
*/
019.
public
class
SlideListView
extends
ListView
{
020.
/**
021.
*
当前滑动的ListView position
022.
*/
023.
private
int
slidePosition;
024.
/**
025.
*
手指按下X的坐标
026.
*/
027.
private
int
downY;
028.
/**
029.
*
手指按下Y的坐标
030.
*/
031.
private
int
downX;
032.
/**
033.
*
屏幕宽度
034.
*/
035.
private
int
screenWidth;
036.
/**
037.
*
ListView的item
038.
*/
039.
private
View
itemView;
040.
/**
041.
*
滑动类
042.
*/
043.
private
Scroller
scroller;
044.
private
static
final
int
SNAP_VELOCITY
=
600
;
045.
/**
046.
*
速度追踪对象
047.
*/
048.
private
VelocityTracker
velocityTracker;
049.
/**
050.
*
是否响应滑动,默认为不响应
051.
*/
052.
private
boolean
isSlide
=
false
;
053.
/**
054.
*
认为是用户滑动的最小距离
055.
*/
056.
private
int
mTouchSlop;
057.
/**
058.
*
移除item后的回调接口
059.
*/
060.
private
RemoveListener
mRemoveListener;
061.
/**
062.
*
标示是否移除
063.
*/
064.
private
boolean
isRemove
=
false
;
065.
/**
066.
*
用来指示item滑出屏幕的方向,向左或者向右,用一个枚举值来标记
067.
*/
068.
private
RemoveDirection
removeDirection;
069.
070.
//
滑动删除方向的枚举值
071.
public
enum
RemoveDirection
{
072.
RIGHT,
LEFT, NONE;
073.
}
074.
075.
076.
public
SlideListView(Context
context) {
077.
this
(context,
null
);
078.
}
079.
080.
public
SlideListView(Context
context, AttributeSet attrs) {
081.
this
(context,
attrs,
0
);
082.
}
083.
084.
public
SlideListView(Context
context, AttributeSet attrs,
int
defStyle)
{
085.
super
(context,
attrs, defStyle);
086.
screenWidth
= ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
087.
scroller
=
new
Scroller(context);
088.
mTouchSlop
= ViewConfiguration.get(getContext()).getScaledTouchSlop();
089.
}
090.
091.
/**
092.
*
设置滑动删除的回调接口
093.
*
@param removeListener
094.
*/
095.
public
void
setRemoveListener(RemoveListener
removeListener) {
096.
this
.mRemoveListener
= removeListener;
097.
}
098.
099.
/**
100.
*
分发事件,主要做的是判断点击的是那个item, 以及通过postDelayed来设置响应左右滑动事件
101.
*/
102.
@Override
103.
public
boolean
dispatchTouchEvent(MotionEvent
event) {
104.
switch
(event.getAction())
{
105.
case
MotionEvent.ACTION_DOWN:
{
106.
System.out.println(
"dispatch-->"
+
"down"
);
107.
addVelocityTracker(event);
108.
109.
//
假如scroller滚动还没有结束,我们直接返回
110.
if
(!scroller.isFinished())
{
111.
return
false
;
112.
}
113.
downX
= (
int
)
event.getX();
114.
downY
= (
int
)
event.getY();
115.
116.
slidePosition
= pointToPosition(downX, downY);
117.
118.
//
无效的position, 不做任何处理
119.
if
(slidePosition
== AdapterView.INVALID_POSITION) {
120.
return
super
.dispatchTouchEvent(event);
121.
}
122.
123.
//
获取我们点击的item view
124.
itemView
= getChildAt(slidePosition - getFirstVisiblePosition());
125.
break
;
126.
}
127.
case
MotionEvent.ACTION_MOVE:
{
128.
System.out.println(
"dispatch-->"
+
"move"
);
129.
if
(Math.abs(getScrollVelocity())
> SNAP_VELOCITY
130.
||
(Math.abs(event.getX() - downX) > mTouchSlop && Math
131.
.abs(event.getY()
- downY) < mTouchSlop)) {
132.
isSlide
=
true
;
133.
134.
}
135.
break
;
136.
}
137.
case
MotionEvent.ACTION_UP:
138.
recycleVelocityTracker();
139.
break
;
140.
}
141.
142.
return
super
.dispatchTouchEvent(event);
143.
}
144.
145.
/**
146.
*
往右滑动,getScrollX()返回的是左边缘的距离,就是以View左边缘为原点到开始滑动的距离,所以向右边滑动为负值
147.
*/
148.
private
void
scrollRight()
{
149.
removeDirection
= RemoveDirection.RIGHT;
150.
final
int
delta
= (screenWidth + itemView.getScrollX());
151.
//
调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item
152.
scroller.startScroll(itemView.getScrollX(),
0
,
-delta,
0
,
153.
Math.abs(delta));
154.
postInvalidate();
//
刷新itemView
155.
}
156.
157.
/**
158.
*
向左滑动,根据上面我们知道向左滑动为正值
159.
*/
160.
private
void
scrollLeft()
{
161.
removeDirection
= RemoveDirection.LEFT;
162.
final
int
delta
= (screenWidth - itemView.getScrollX());
163.
//
调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item
164.
scroller.startScroll(itemView.getScrollX(),
0
,
delta,
0
,
165.
Math.abs(delta));
166.
postInvalidate();
//
刷新itemView
167.
}
168.
169.
/**
170.
*
滑动会原来的位置
171.
*/
172.
private
void
scrollBack(){
173.
removeDirection
= RemoveDirection.NONE;
174.
scroller.startScroll(itemView.getScrollX(),
0
,
-itemView.getScrollX(),
0
,
175.
Math.abs(itemView.getScrollX()));
176.
postInvalidate();
//
刷新itemView
177.
}
178.
179.
/**
180.
*
根据手指滚动itemView的距离来判断是滚动到开始位置还是向左或者向右滚动
181.
*/
182.
private
void
scrollByDistanceX()
{
183.
//
如果向左滚动的距离大于屏幕的二分之一,就让其删除
184.
if
(itemView.getScrollX()
>= screenWidth /
2
)
{
185.
scrollLeft();
186.
}
else
if
(itemView.getScrollX()
<= -screenWidth /
2
)
{
187.
scrollRight();
188.
}
else
{
189.
//
滚回到原始位置
190.
scrollBack();
191.
}
192.
193.
}
194.
195.
/**
196.
*
处理我们拖动ListView item的逻辑
197.
*/
198.
@Override
199.
public
boolean
onTouchEvent(MotionEvent
ev) {
200.
if
(isSlide
&& slidePosition != AdapterView.INVALID_POSITION) {
201.
System.out.println(
"touch-->"
+
"开始"
);
202.
requestDisallowInterceptTouchEvent(
true
);
203.
addVelocityTracker(ev);
204.
final
int
action
= ev.getAction();
205.
int
x
= (
int
)
ev.getX();
206.
switch
(action)
{
207.
case
MotionEvent.ACTION_DOWN:
208.
System.out.println(
"touch-->"
+
"down"
);
209.
break
;
210.
case
MotionEvent.ACTION_MOVE:
211.
System.out.println(
"touch-->"
+
"move"
);
212.
MotionEvent
cancelEvent = MotionEvent.obtain(ev);
213.
cancelEvent.setAction(MotionEvent.ACTION_CANCEL
|
214.
(ev.getActionIndex()<<
MotionEvent.ACTION_POINTER_INDEX_SHIFT));
215.
onTouchEvent(cancelEvent);
216.
217.
int
deltaX
= downX - x;
218.
219.
//
手指拖动itemView滚动, deltaX大于0向左滚动,小于0向右滚
220.
itemView.scrollTo(deltaX,
0
);
221.
//
根据手指滑动的距离,调整透明度
222.
itemView.setAlpha(1f
- Math.abs((
float
)deltaX/screenWidth));
223.
224.
return
true
;
//拖动的时候ListView不滚动
225.
case
MotionEvent.ACTION_UP:
226.
System.out.println(
"touch-->"
+
"up"
);
227.
//
手指离开的时候就不响应左右滚动
228.
isSlide
=
false
;
229.
int
velocityX
= getScrollVelocity();
230.
if
(velocityX
> SNAP_VELOCITY) {
231.
scrollRight();
232.
}
else
if
(velocityX
< -SNAP_VELOCITY) {
233.
scrollLeft();
234.
}
else
{
235.
scrollByDistanceX();
236.
}
237.
238.
recycleVelocityTracker();
239.
240.
break
;
241.
}
242.
}
243.
244.
//否则直接交给ListView来处理onTouchEvent事件
245.
return
super
.onTouchEvent(ev);
246.
}
247.
248.
@Override
249.
public
void
computeScroll()
{
250.
//
调用startScroll的时候scroller.computeScrollOffset()返回true,
251.
if
(scroller.computeScrollOffset())
{
252.
//
让ListView item根据当前的滚动偏移量进行滚动
253.
itemView.scrollTo(scroller.getCurrX(),
scroller.getCurrY());
254.
255.
itemView.setAlpha(1f
- Math.abs((
float
)scroller.getCurrX()/screenWidth));
256.
257.
postInvalidate();
258.
259.
//
滚动动画结束的时候调用回调接口
260.
if
(scroller.isFinished()
&& removeDirection != RemoveDirection.NONE) {
261.
if
(mRemoveListener
==
null
)
{
262.
throw
new
NullPointerException(
"RemoveListener
is null, we should called setRemoveListener()"
);
263.
}
264.
itemView.scrollTo(
0
,
0
);
265.
itemView.setAlpha(1f);
266.
mRemoveListener.removeItem(removeDirection,
slidePosition);
267.
}
268.
}
269.
}
270.
271.
/**
272.
*
添加用户的速度跟踪器
273.
*
274.
*
@param event
275.
*/
276.
private
void
addVelocityTracker(MotionEvent
event) {
277.
if
(velocityTracker
==
null
)
{
278.
velocityTracker
= VelocityTracker.obtain();
279.
}
280.
281.
velocityTracker.addMovement(event);
282.
}
283.
284.
/**
285.
*
移除用户速度跟踪器
286.
*/
287.
private
void
recycleVelocityTracker()
{
288.
if
(velocityTracker
!=
null
)
{
289.
velocityTracker.recycle();
290.
velocityTracker
=
null
;
291.
}
292.
}
293.
294.
/**
295.
*
获取X方向的滑动速度,大于0向右滑动,反之向左
296.
*
297.
*
@return
298.
*/
299.
private
int
getScrollVelocity()
{
300.
velocityTracker.computeCurrentVelocity(
1000
);
301.
int
velocity
= (
int
)
velocityTracker.getXVelocity();
302.
return
velocity;
303.
}
304.
305.
/**
306.
*
307.
*
当ListView item滑出屏幕,回调这个接口
308.
*
我们需要在回调方法removeItem()中移除该Item,然后刷新ListView
309.
*
310.
*
@author xiaanming
311.
*
312.
*/
313.
public
interface
RemoveListener
{
314.
public
void
removeItem(RemoveDirection
direction,
int
position);
315.
}
316.
317.
}
001.
package
com.example.testslidelistview;
002.
003.
import
android.content.Context;
004.
import
android.util.AttributeSet;
005.
import
android.view.MotionEvent;
006.
import
android.view.View;
007.
import
android.view.ViewConfiguration;
008.
import
android.widget.AdapterView;
009.
import
android.widget.ListView;
010.
import
android.widget.Scroller;
011.
012.
/**
013.
*
侧向滑出菜单的ListView
014.
*
使用请注意与ListView的Item的布局配合,
015.
*
该效果的实现是基于在Item的布局中通过设置PaddingLeft和PaddingRight来隐藏左右菜单的,
016.
*
所以使用此ListView时,请务必在布局Item时使用PaddingLeft和PaddingRight;
017.
*
或者自己改写此ListView,已达到想要的实现方式
018.
*
@author zhangshuo
019.
*/
020.
public
class
SlideListView2
extends
ListView
{
021.
022.
/**禁止侧滑模式*/
023.
public
static
int
MOD_FORBID
=
0
;
024.
/**从左向右滑出菜单模式*/
025.
public
static
int
MOD_LEFT
=
1
;
026.
/**从右向左滑出菜单模式*/
027.
public
static
int
MOD_RIGHT
=
2
;
028.
/**左右均可以滑出菜单模式*/
029.
public
static
int
MOD_BOTH
=
3
;
030.
/**当前的模式*/
031.
private
int
mode
= MOD_FORBID;
032.
/**左侧菜单的长度*/
033.
private
int
leftLength
=
0
;
034.
/**右侧菜单的长度*/
035.
private
int
rightLength
=
0
;
036.
037.
/**
038.
*
当前滑动的ListView position
039.
*/
040.
private
int
slidePosition;
041.
/**
042.
*
手指按下X的坐标
043.
*/
044.
private
int
downY;
045.
/**
046.
*
手指按下Y的坐标
047.
*/
048.
private
int
downX;
049.
/**
050.
*
ListView的item
051.
*/
052.
private
View
itemView;
053.
/**
054.
*
滑动类
055.
*/
056.
private
Scroller
scroller;
057.
/**
058.
*
认为是用户滑动的最小距离
059.
*/
060.
private
int
mTouchSlop;
061.
062.
/**
063.
*
判断是否可以侧向滑动
064.
*/
065.
private
boolean
canMove
=
false
;
066.
/**
067.
*
标示是否完成侧滑
068.
*/
069.
private
boolean
isSlided
=
false
;
070.
071.
public
SlideListView2(Context
context) {
072.
this
(context,
null
);
073.
}
074.
075.
public
SlideListView2(Context
context, AttributeSet attrs) {
076.
this
(context,
attrs,
0
);
077.
}
078.
079.
public
SlideListView2(Context
context, AttributeSet attrs,
int
defStyle)
{
080.
super
(context,
attrs, defStyle);
081.
scroller
=
new
Scroller(context);
082.
mTouchSlop
= ViewConfiguration.get(getContext()).getScaledTouchSlop();
083.
}
084.
085.
/**
086.
*
初始化菜单的滑出模式
087.
*
@param mode
088.
*/
089.
public
void
initSlideMode(
int
mode){
090.
this
.mode
= mode;
091.
}
092.
093.
/**
094.
*
处理我们拖动ListView item的逻辑
095.
*/
096.
@Override
097.
public
boolean
onTouchEvent(MotionEvent
ev) {
098.
099.
final
int
action
= ev.getAction();
100.
int
lastX
= (
int
)
ev.getX();
101.
102.
switch
(action)
{
103.
case
MotionEvent.ACTION_DOWN:
104.
System.out.println(
"touch-->"
+
"down"
);
105.
106.
/*当前模式不允许滑动,则直接返回,交给ListView自身去处理*/
107.
if
(
this
.mode
== MOD_FORBID){
108.
return
super
.onTouchEvent(ev);
109.
}
110.
111.
//
如果处于侧滑完成状态,侧滑回去,并直接返回
112.
if
(isSlided)
{
113.
scrollBack();
114.
return
false
;
115.
}
116.
//
假如scroller滚动还没有结束,我们直接返回
117.
if
(!scroller.isFinished())
{
118.
return
false
;
119.
}
120.
downX
= (
int
)
ev.getX();
121.
downY
= (
int
)
ev.getY();
122.
123.
slidePosition
= pointToPosition(downX, downY);
124.
125.
//
无效的position, 不做任何处理
126.
if
(slidePosition
== AdapterView.INVALID_POSITION) {
127.
return
super
.onTouchEvent(ev);
128.
}
129.
130.
//
获取我们点击的item view
131.
itemView
= getChildAt(slidePosition - getFirstVisiblePosition());
132.
133.
/*此处根据设置的滑动模式,自动获取左侧或右侧菜单的长度*/
134.
if
(
this
.mode
== MOD_BOTH){
135.
this
.leftLength
= -itemView.getPaddingLeft();
136.
this
.rightLength
= -itemView.getPaddingRight();
137.
}
else
if
(
this
.mode
== MOD_LEFT){
138.
this
.leftLength
= -itemView.getPaddingLeft();
139.
}
else
if
(
this
.mode
== MOD_RIGHT){
140.
this
.rightLength
= -itemView.getPaddingRight();
141.
}
142.
143.
break
;
144.
case
MotionEvent.ACTION_MOVE:
145.
System.out.println(
"touch-->"
+
"move"
);
146.
147.
if
(!canMove
148.
&&
slidePosition != AdapterView.INVALID_POSITION
149.
&&
(Math.abs(ev.getX() - downX) > mTouchSlop && Math.abs(ev
150.
.getY()
- downY) < mTouchSlop)) {
151.
int
offsetX
= downX - lastX;
152.
if
(offsetX
>
0
&&
(
this
.mode
== MOD_BOTH ||
this
.mode
== MOD_RIGHT)){
153.
/*从右向左滑*/
154.
canMove
=
true
;
155.
}
else
if
(offsetX
<
0
&&
(
this
.mode
== MOD_BOTH ||
this
.mode
== MOD_LEFT)){
156.
/*从左向右滑*/
157.
canMove
=
true
;
158.
}
else
{
159.
canMove
=
false
;
160.
}
161.
/*此段代码是为了避免我们在侧向滑动时同时出发ListView的OnItemClickListener时间*/
162.
MotionEvent
cancelEvent = MotionEvent.obtain(ev);
163.
cancelEvent
164.
.setAction(MotionEvent.ACTION_CANCEL
165.
|
(ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
166.
onTouchEvent(cancelEvent);
167.
}
168.
if
(canMove)
{
169.
/*设置此属性,可以在侧向滑动时,保持ListView不会上下滚动*/
170.
requestDisallowInterceptTouchEvent(
true
);
171.
172.
//
手指拖动itemView滚动, deltaX大于0向左滚动,小于0向右滚
173.
int
deltaX
= downX - lastX;
174.
if
(deltaX
<
0
&&
(
this
.mode
== MOD_BOTH ||
this
.mode
== MOD_LEFT)){
175.
/*向左滑*/
176.
itemView.scrollTo(deltaX,
0
);
177.
}
else
if
(deltaX
>
0
&&
(
this
.mode
== MOD_BOTH ||
this
.mode
== MOD_RIGHT)){
178.
/*向右滑*/
179.
itemView.scrollTo(deltaX,
0
);
180.
}
else
{
181.
itemView.scrollTo(
0
,
0
);
182.
}
183.
return
true
;
//
拖动的时候ListView不滚动
184.
}
185.
case
MotionEvent.ACTION_UP:
186.
System.out.println(
"touch-->"
+
"up"
);
187.
if
(canMove){
188.
canMove
=
false
;
189.
scrollByDistanceX();
190.
}
191.
break
;
192.
}
193.
194.
//
否则直接交给ListView来处理onTouchEvent事件
195.
return
super
.onTouchEvent(ev);
196.
}
197.
198.
/**
199.
*
根据手指滚动itemView的距离来判断是滚动到开始位置还是向左或者向右滚动
200.
*/
201.
private
void
scrollByDistanceX()
{
202.
/*当前模式不允许滑动,则直接返回*/
203.
if
(
this
.mode
== MOD_FORBID){
204.
return
;
205.
}
206.
if
(itemView.getScrollX()
>
0
&&
(
this
.mode
== MOD_BOTH ||
this
.mode
== MOD_RIGHT)){
207.
/*从右向左滑*/
208.
if
(itemView.getScrollX()
>= rightLength /
2
)
{
209.
scrollLeft();
210.
}
else
{
211.
//
滚回到原始位置
212.
scrollBack();
213.
}
214.
}
else
if
(itemView.getScrollX()
<
0
&&
(
this
.mode
== MOD_BOTH ||
this
.mode
== MOD_LEFT)){
215.
/*从左向右滑*/
216.
if
(itemView.getScrollX()
<= -leftLength /
2
)
{
217.
scrollRight();
218.
}
else
{
219.
//
滚回到原始位置
220.
scrollBack();
221.
}
222.
}
else
{
223.
//
滚回到原始位置
224.
scrollBack();
225.
}
226.
227.
}
228.
229.
/**
230.
*
往右滑动,getScrollX()返回的是左边缘的距离,就是以View左边缘为原点到开始滑动的距离,所以向右边滑动为负值
231.
*/
232.
private
void
scrollRight()
{
233.
isSlided
=
true
;
234.
final
int
delta
= (leftLength + itemView.getScrollX());
235.
//
调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item
236.
scroller.startScroll(itemView.getScrollX(),
0
,
-delta,
0
,
237.
Math.abs(delta));
238.
postInvalidate();
//
刷新itemView
239.
}
240.
241.
/**
242.
*
向左滑动,根据上面我们知道向左滑动为正值
243.
*/
244.
private
void
scrollLeft()
{
245.
isSlided
=
true
;
246.
final
int
delta
= (rightLength - itemView.getScrollX());
247.
//
调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item
248.
scroller.startScroll(itemView.getScrollX(),
0
,
delta,
0
,
249.
Math.abs(delta));
250.
postInvalidate();
//
刷新itemView
251.
}
252.
253.
/**
254.
*
滑动会原来的位置
255.
*/
256.
private
void
scrollBack()
{
257.
isSlided
=
false
;
258.
scroller.startScroll(itemView.getScrollX(),
0
,
-itemView.getScrollX(),
259.
0
,
Math.abs(itemView.getScrollX()));
260.
postInvalidate();
//
刷新itemView
261.
}
262.
263.
@Override
264.
public
void
computeScroll()
{
265.
//
调用startScroll的时候scroller.computeScrollOffset()返回true,
266.
if
(scroller.computeScrollOffset())
{
267.
//
让ListView item根据当前的滚动偏移量进行滚动
268.
itemView.scrollTo(scroller.getCurrX(),
scroller.getCurrY());
269.
270.
postInvalidate();
271.
}
272.
}
273.
274.
/**
275.
*
提供给外部调用,用以将侧滑出来的滑回去
276.
*/
277.
public
void
slideBack()
{
278.
this
.scrollBack();
279.
}
280.
281.
}
注意侧滑菜单ListView的使用需要配合Item布局(主要是PaddingLeft和PaddingRight这两个属性),Item布局如下:
001.
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
002.
xmlns:tools=
"http://schemas.android.com/tools"
003.
android:layout_width=
"match_parent"
004.
android:layout_height=
"match_parent"
005.
android:paddingLeft=
"-181dp"
006.
android:paddingRight=
"-180dp"
007.
android:background=
"@color/wheat"
008.
android:orientation=
"horizontal"
>
009.
010.
<LinearLayout
011.
android:id=
"@+id/llayout_left"
012.
android:layout_width=
"180dp"
013.
android:layout_height=
"match_parent"
>
014.
015.
<RelativeLayout
016.
android:id=
"@+id/delete1"
017.
android:layout_width=
"90dp"
018.
android:layout_height=
"match_parent"
019.
android:background=
"@color/slategray"
020.
android:clickable=
"true"
>
021.
022.
<TextView
023.
android:layout_width=
"wrap_content"
024.
android:layout_height=
"wrap_content"
025.
android:layout_centerInParent=
"true"
026.
android:gravity=
"center"
027.
android:text=
"左删除"
028.
android:textColor=
"@color/floralwhite"
029.
android:textSize=
"15sp"
/>
030.
</RelativeLayout>
031.
032.
<RelativeLayout
033.
android:id=
"@+id/other1"
034.
android:layout_width=
"90dp"
035.
android:layout_height=
"match_parent"
036.
android:background=
"@color/tomato"
037.
android:clickable=
"true"
>
038.
039.
<TextView
040.
android:layout_width=
"wrap_content"
041.
android:layout_height=
"wrap_content"
042.
android:layout_centerInParent=
"true"
043.
android:gravity=
"center"
044.
android:text=
"左其他"
045.
android:textColor=
"@color/floralwhite"
046.
android:textSize=
"15sp"
/>
047.
</RelativeLayout>
048.
</LinearLayout>
049.
050.
051.
<RelativeLayout
052.
android:layout_width=
"match_parent"
053.
android:layout_height=
"match_parent"
>
054.
<LinearLayout
055.
android:layout_width=
"match_parent"
056.
android:layout_height=
"match_parent"
057.
android:layout_toLeftOf=
"@+id/llayout_right"
058.
android:orientation=
"vertical"
>
059.
060.
<TextView
061.
android:id=
"@+id/title"
062.
android:layout_width=
"match_parent"
063.
android:layout_height=
"wrap_content"
064.
android:gravity=
"center_vertical"
065.
android:paddingLeft=
"10dp"
066.
android:paddingRight=
"10dp"
067.
android:text=
"标题"
068.
android:textColor=
"@color/orange"
069.
android:textSize=
"17sp"
/>
070.
071.
<TextView
072.
android:id=
"@+id/time"
073.
android:layout_width=
"wrap_content"
074.
android:layout_height=
"wrap_content"
075.
android:layout_marginLeft=
"10dp"
076.
android:text=
"时间"
077.
android:textColor=
"@color/black"
078.
android:textSize=
"13sp"
/>
079.
080.
<TextView
081.
android:id=
"@+id/content"
082.
android:layout_width=
"wrap_content"
083.
android:layout_height=
"wrap_content"
084.
android:layout_marginLeft=
"10dp"
085.
android:text=
"内容"
086.
android:textColor=
"@color/black"
087.
android:textSize=
"13sp"
/>
088.
</LinearLayout>
089.
090.
<LinearLayout
091.
android:id=
"@+id/llayout_right"
092.
android:layout_width=
"180dp"
093.
android:layout_height=
"match_parent"
094.
android:layout_alignParentRight=
"true"
>
095.
096.
<RelativeLayout
097.
android:id=
"@+id/other2"
098.
android:layout_width=
"90dp"
099.
android:layout_height=
"match_parent"
100.
android:background=
"@color/slategray"
101.
android:clickable=
"true"
>
102.
103.
<TextView
104.
android:layout_width=
"wrap_content"
105.
android:layout_height=
"wrap_content"
106.
android:layout_centerInParent=
"true"
107.
android:gravity=
"center"
108.
android:text=
"右其他"
109.
android:textColor=
"@color/floralwhite"
110.
android:textSize=
"15sp"
/>
111.
</RelativeLayout>
112.
113.
<RelativeLayout
114.
android:id=
"@+id/delete2"
115.
android:layout_width=
"90dp"
116.
android:layout_height=
"match_parent"
117.
android:background=
"@color/tomato"
118.
android:clickable=
"true"
>
119.
120.
<TextView
121.
android:layout_width=
"wrap_content"
122.
android:layout_height=
"wrap_content"
123.
android:layout_centerInParent=
"true"
124.
android:gravity=
"center"
125.
android:text=
"右删除"
126.
android:textColor=
"@color/floralwhite"
127.
android:textSize=
"15sp"
/>
128.
</RelativeLayout>
129.
</LinearLayout>
130.
</RelativeLayout>
131.
132.
133.
</LinearLayout>
截图: