一段文字,如果行间距很小的话看着就会很不舒服,我们在使用word文档的时候行间距是可以自己调整的,那么在Android开发的过程中如果一大段很长的文字如何设置行间距呢,很简单只需要一行代码:
android:lineSpacingExtra="3dp"
分享三张效果图:
第一张,没有设置行间距的,使用系统默认的效果:
![3dp](/upload/news/201610/20160626220007249.png)
第三张,设置为10dp的效果,更明显:
![10dp](/upload/news/201610/20160626220009569.png)
在使用QQ的过程中我们会发现一个很短的界面也是可以上下拖动的,这就是带有阻尼效果功能实现,要实现这样的功能呢,系统的ScrollView是没法实现的,必须要自定义继承于ScrollView的控件,先来看下效果图。
先来看看布局:
<?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" >
<frame.zmit.cn.stretchscrollview.StretchScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6E6E6"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="16sp"
android:background="#FFFFFF"
android:gravity="center"
android:text="5" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#E6E6E6" />
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="16sp"
android:background="#FFFFFF"
android:gravity="center"
android:text="5" />
</LinearLayout>
</frame.zmit.cn.stretchscrollview.StretchScrollView>
</LinearLayout>
Activity啥也没有,就不贴了
下面贴上自定义的StretchScrollView
package frame.zmit.cn.stretchscrollview;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;
/**
* A ScrollView which can scroll to (0,0) when pull down or up.
*
* @author markmjw
* @date 2014-04-30
*/
public class StretchScrollView extends ScrollView {
private static final int MSG_REST_POSITION = 0x01;
/** The max scroll height. */
private static final int MAX_SCROLL_HEIGHT = 600;
/** Damping, the smaller the greater the resistance */
private static final float SCROLL_RATIO = 0.4f;
private View mChildRootView;
private float mTouchY;
private boolean mTouchStop = false;
private int mScrollY = 0;
private int mScrollDy = 0;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (MSG_REST_POSITION == msg.what) {
if (mScrollY != 0 && mTouchStop) {
mScrollY -= mScrollDy;
if ((mScrollDy < 0 && mScrollY > 0) || (mScrollDy > 0 && mScrollY < 0)) {
mScrollY = 0;
}
mChildRootView.scrollTo(0, mScrollY);
// continue scroll after 20ms
sendEmptyMessageDelayed(MSG_REST_POSITION, 20);
}
}
}
};
public StretchScrollView(Context context) {
super(context);
init();
}
public StretchScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public StretchScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
// set scroll mode
setOverScrollMode(OVER_SCROLL_NEVER);
}
@Override
protected void onFinishInflate() {
if (getChildCount() > 0) {
// when finished inflating from layout xml, get the first child view
mChildRootView = getChildAt(0);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mTouchY = ev.getY();
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (null != mChildRootView) {
doTouchEvent(ev);
}
return super.onTouchEvent(ev);
}
private void doTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
mScrollY = mChildRootView.getScrollY();
if (mScrollY != 0) {
mTouchStop = true;
mScrollDy = (int) (mScrollY / 10.0f);
mHandler.sendEmptyMessage(MSG_REST_POSITION);
}
break;
case MotionEvent.ACTION_MOVE:
float nowY = ev.getY();
int deltaY = (int) (mTouchY - nowY);
mTouchY = nowY;
if (isNeedMove()) {
int offset = mChildRootView.getScrollY();
if (offset < MAX_SCROLL_HEIGHT && offset > -MAX_SCROLL_HEIGHT) {
mChildRootView.scrollBy(0, (int) (deltaY * SCROLL_RATIO));
mTouchStop = false;
}
}
break;
default:
break;
}
}
private boolean isNeedMove() {
int viewHeight = mChildRootView.getMeasuredHeight();
int scrollHeight = getHeight();
int offset = viewHeight - scrollHeight;
int scrollY = getScrollY();
return scrollY == 0 || scrollY == offset;
}
}
Acache类下载地址:http://pan.baidu.com/s/1gfI0A9X
1、创建Acache实例
Acache acache;
acache = Acache.get(this, “main”);
2、将数据保存起来(内存和文件)
acache.put(key,value,time);
前两个无需赘述,键值对,最后一个time,传入int类型,单位为秒,代表缓存存在的时间,超出这个时间,就会清除掉缓存的数据。
3、获取缓存的数据
以一个例子来描述这个问题:
代码如下 | 复制代码 |
public class MainActivity extends Activity { |
当我第一次进入的时候,控制台打印如下:
![](/upload/news/201610/image5768e3ea547911.31130873.jpg)
当我立即退出又进去,打印如下:
当我延迟了十秒左右再进去,又提示如下:
这样可以证明缓存可用,并且缓存的时间也有效果。
关于Android实现倒计时呢,对于很多人来说一直是一个头疼的问题,当然我也一样,在开发倒计时功能的时候会遇到很多棘手甚至奇葩的问题或者bug,我在开发倒计时的时候,如果当前页面只有一个倒计时,那么就不是很复杂,开发出来的效果也不是会非常糟糕,网上会有很多的教程实现。如果要在ListView或者GridView中实现倒计时呢,真的是一个很头疼的问题,我在这其中吃了很多苦头和走了很多弯路,还有死了很多脑细胞。下面我来总结一下在ListView中开发倒计时的问题。
先来展示一下我开发出来的效果图,这是在GridView中实现的:
![view](/upload/news/201610/20160618170209956.png)
一:数据混乱
描述一下什么叫数据混乱,比如说我有二十个倒计时在运行,第一个已经结束了,其他的都没有结束,我在往下滑动的时候,发现下面的某些倒计时也已经结束了,再循环滑动,又有不同的倒计时结束了,然后有时候本来已经结束的倒计时又开始倒计时了,这些就是在滑动过程中引发的数据混乱的问题。
二:倒计时重新开始:
描述一下什么叫倒计时重新开始,比如我的listview的第一个item在进行倒计时,从60秒开始减少,当减少到假如说40秒的时候,我往下滑动,使第一个item超出屏幕可见之外,再往上滑回第一个item,这时候你会发现倒计时又开始从60秒重新开始倒计时了,这是因为你的倒计时的时间如果是死的,在滑动回来的时候界面重绘,数据重新加载,所以倒计时又开始重新倒计时。
三:卡顿,超时,甚至崩溃:
这个就不用描述了,倒计时很多的话,就会出现卡顿的情况,如果非常多,手机就会死机崩溃,我在下载其他知名APP存在倒计时的界面进行使用时,一直上拉加载更多数据,出现很多的倒计时,发现也会卡顿,最后界面不能操作死机了。
四:倒计时不易控制和判断:
既然进行倒计时,那么我们就得需要监听倒计时什么时候结束,结束之后进行相应的操作,这是其一。其二,我们需要灵活的使用倒计时,比如是显示“年”、“天”、“时”、“分”、“秒”、“毫秒”等等,都要比较好控制和修改最好。
要解决这些问题呢,其实是很困难的,我查过很多的方式来实现发现都不是很好,甚至不能解决问题。最后呢,我找到了一个第三方依赖库,在github上也有,具体地址我找不到了,不过在it蓝豹上也有,这
在使用这个方式实现倒计时的时候,只解决了第三和第四的问题,说实话卡顿和控制方面解决了就好多了。另外我在使用的时候发现也会出现第一和第二个问题,当然在他的项目里也有在listview中的Demo,不过有点复杂我就没有深度研究,按照最基本的继承BaseAdapter和ViewHolder优化实现的方式来开发会出现数据错乱和重新开始的bug,最后我就在想能不能把倒计时时间来转化成本地时间进行倒计时,最后的结果是完全可以,不过可能会有一点误差,神奇的是连同数据混乱的bug也消失了。
比如说倒计时需要100秒,那么我就拿本地的时间加上这100秒作为结束时间,然后在倒计时需要开始的时候,拿上这结束时间减去本地时间就是需要倒计时的时间。
具体的代码如下:
具体的代码如下:
本地时间:long curTime = System.currentTimeMillis();//注意:单位毫秒
结束时间:curTime +(100*1000);//注意:单位毫秒,把100秒转化为毫秒
在需要倒计时的地方开启倒计时:
cv_countdownView.start(itemData.getEndtime() - System.currentTimeMillis());
同时,在监听方面,此依赖提供了一个接口:
代码如下:
cv_countdownView.setOnCountdownEndListener(new CountdownView.OnCountdownEndListener() {
@Override public void onEnd(CountdownView cv) {
//时间结束 }
});
在布局中使用也非常简单,
<cn.iwgang.countdownview.CountdownView
android:id="@+id/cv_countdownView_one"
android:layout_width="90dp"
android:layout_height="30dp"
android:layout_gravity="center_horizontal"
app:isShowDay="false"
app:isShowHour="false"
app:isShowMillisecond="true"
app:isShowMinute="true"
app:isShowSecond="true"
app:suffixGravity="center"
app:suffixTextColor="#FFFFFF"
app:suffixTextSize="14sp"
app:timeTextColor="#FFFFFF"
app:timeTextSize="14sp" />;
需要显示什么就写为true,否则false就可以了。
我觉得最关键的还是流畅不卡顿最重要。
好了,这就是我在开发倒计时的时候遇到的问题总结,希望能帮助到更多的人。谢谢,此文章是我一字一字打出来的,转载请注明。谢谢
原文来自 :http://blog.it985.com/16781.html