分享Android上dip、dp、px、sp等单位详解

 更新时间:2016年9月20日 20:00  点击:1448
如果有各位在做手机应用开发的朋友可能需要了解一下关于Android上dip、dp、px、sp等单位了,有兴趣的同学可以看看本文章。

[ dip: device independent pixels(设备独立像素).

不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。

px: pixels(像素). 不同设备显示效果相同,一般我们HVGA代表320x480像素,这个用的比较多。 

pt: point,是一个标准的长度单位,1pt=1/72英寸,用于印刷业,非常简单易用;

sp: scaled pixels(放大像素). 主要用于字体显示best for textsize。 

========================= 

关于换算(以 sp 和 pt 为例)  

查看 TextView 等类的源码,可知:  

case COMPLEX_UNIT_PX:  

return value;  

case COMPLEX_UNIT_SP:  

return value * metrics.scaledDensity;  

case COMPLEX_UNIT_PT:  

return value * metrics.xdpi * (1.0f/72); 

--------------------------  

scaledDensity = DENSITY_DEVICE / (float) DENSITY_DEFAULT;

xdpi = DENSITY_DEVICE; 

-------------------------- 

DENSITY_DEFAULT = DENSITY_MEDIUM = 160;  

============================================  

所以: 假设 pt 和 sp 取相同的值 1,则可设 1pt 和 1sp 之间系数为 x,  

1 * DENSITY_DEVICE / 72 = x * 1 * DENSITY_DEVICE / 160 =>  

x = 160 / 72 = 2.2222  

也就是说在 Android 中, 1pt 大概等于 2.22sp  

===================================================================

 什么是Dip和Sp 

 过去,程序员通常以像素为单位设计计算机用户界面。例如,定义一个宽度为300像素的表

单字段,列之间的间距为5个像素,图标大小为16×16像素 等。这样处理的问题在于,如

果在一个每英寸点数(dpi)更高的新显示器上运行该程序,则用户界面会显得很小。在有

些情况下,用户界面可能会小到难以看清 内容。   

与分辨率无关的度量单位可以解决这一问题。Android支持下列所有单位。  

px(像素):屏幕上的点。  

in(英寸):长度单位。  

mm(毫米):长度单位。  

pt(磅):1/72英寸。  

dp(与密度无关的像素):一种基于屏幕密度的抽象单位。在每英寸160点的显示器上,1dp= 1px。  

dip:与dp相同,多用于android/ophone示例中。  

sp(与刻度无关的像素):与dp类似,但是可以根据用户的字体大小首选项进行缩放。  

为了使用户界面能够在现在和将来的显示器类型上正常显示,建议大家始终使用sp作为文 字大小的单位,将dip作为其他元素的单位。当然,也可以考虑使用矢量图形,而不是用位图

 

android(安卓)手机铃声设置源码分析,设置铃声之前,要先知道有哪些系统铃声,所以需要扫描,android提供了xxx.media这个contentProvider为此服务,对应的数据库为internal.db/external-xx.db

代码其实没有几行,这里简单记录下学习的过程.

Android系统启动时会扫描系统与SD卡中的对媒体文件,分别存入数据库sqlite中,以contentProvider的形式对外提供服务

路径:/data/data/com.android.providers.media/databases/XXX...

可以看到有2个db文件, 一个是系统的,一个是sd卡里的

用SQLite Expert打开internal.db,部分截图如下:

这里面记录了音频audio、视频video、图片images的相关数据信息,我们以音频audio为例,蓝色部分audio_meta就是audio数据表,打开之后就可以看到详细信息了,里面列出了系统内部的所有音频文件,各个字段在android.provider.MediaStore中都定义有相应的常量,如id --- MediaStore.Audio.Media._ID.

 

而这里面有想说下这四个字段

含义在源码里都有说明,看了一遍数据,发现这四个字段同时有且仅有一个字段为1,也就是对于一个多媒体文件只能是这四种中的一种,默认为0,如果是某种类型,则android系统默认置为1,所以也就明白了为什么很多扫描系统通知或者来电铃声的示例代码中,都会有一个类似的条件语句:is_notification = 1.

如:

/**
     * 扫描系统内部通知铃声
     */
   

 代码如下 复制代码

private void scannerMediaFile() {
        ContentResolver cr = this.getContentResolver();
        Cursor cursor = cr.query(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,
                new String[] { MediaStore.Audio.Media._ID,
                        MediaStore.Audio.Media.DATA,
                        MediaStore.Audio.Media.TITLE }, "is_notification != ?",
                new String[] { "0" }, "_id asc");

        if (cursor == null) {
            return;
        }

        while (cursor.moveToNext()) {
            data.add(cursor.getString(1));
        }
    }

这里 is_notification != 0,效果是一样的,除非哪天google再定义个2, 3 ......

 

上面扯了些其他的,关于设置铃声的方法,系统提供了一个铃声管理器android.provider.RingtoneManager,其中提供了获取与设置铃声的API

如:

 代码如下 复制代码
Uri uri = RingtoneManager.getActualDefaultRingtoneUri(MediaActivity.this, RingtoneManager.TYPE_NOTIFICATION);可以获取到当前系统的通知铃声uri

第二个参数可以指定获取的铃声类型,还有其他的TYPE_RINGTONE,TYPE_ALARM, TYPE_ALL

设置铃声的API:

 代码如下 复制代码
RingtoneManager.setActualDefaultRingtoneUri(MediaActivity.this,
                        RingtoneManager.TYPE_NOTIFICATION, Uri.parse(data.get(position)));

第二个参数同上,最后一个是指定一个新的Uri, 这里的data.get(position)就是在上面的扫描代码扫描出的所有通知铃声path路径中选泽一个,然后在解析成一个URI对象传入即可

 

那么android是如何获取指定类型的系统铃声呢?

这涉及到另一个类android.provider.Settings

相关源码如下:

 代码如下 复制代码

public static Uri getActualDefaultRingtoneUri(Context context, int type) {
//根据指定的类型获取Settings类中对应的类型,这里RingtoneManager.TYPE_NOTIFICATION对应的为Settings.System.NOTIFICATION_SOUND,其实也就是下面所说的system表中的一个name字段名
        String setting = getSettingForType(type);
        if (setting == null) return null;
//调用Settings类中静态内部类System中的相应方法
        final String uriString = Settings.System.getString(context.getContentResolver(), setting);
        return uriString != null ? Uri.parse(uriString) : null;
    }

 代码如下 复制代码

public synchronized static String getString(ContentResolver resolver, String name) {
//MOVED_TO_SECURE是System类中定义的一个hashSet集合,在Android系统启动时,会初始化30(目前是30)条涉及系统安全的设置数据(如果http代理设置,wifi相关设置),并且存入数据库中,与多媒体的db不同,系统默认存放在settings.db中,路径为/data/data/com.android.providers.settings/databases,具体是存放在settings.db数据库实例的secure表中,用工具打开,可以看到此表中恰好有30条数据。说了那么多,其实这里是检查你所指定的类型也就是db中的字段在不在这个集合中,如果在,则会调用Settings类中的另一个静态内部类Secure中的getString(...)方法
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Secure, returning read-only value.");
                return Secure.getString(resolver, name);
            }
//如果不在那个涉及系统安全的设置集合中,则调用Settings中定义的一个缓存类NameValueCache中的getString(...)
            if (sNameValueCache == null) {
                sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI,
                                                     CALL_METHOD_GET_SYSTEM);
            }
            return sNameValueCache.getString(resolver, name);
        }

//NameValueCache中getString()方法部分代码
Cursor c = null;
            try {
//mUri == "content://settings/system"在NameValueCache初始化时赋值,指定查询的是settings.db中的system表,同理上面提到的Secure类的getString(...)中调用的也是这个缓存类的同名方法,只不过mUri被指定为查询secure表(这2个表中除了id,只有name与value2个字段,分别指定设置的类型与对应的值)
                c = cp.query(mUri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,
                             new String[]{name}, null);
                if (c == null) {
                    Log.w(TAG, "Can't get key " + name + " from " + mUri);
                    return null;
                }

                String value = c.moveToNext() ? c.getString(0) : null;
                synchronized (this) {
//查询完讲name/value键值对放入mValues集合中,当然如果这个集合中已经存在这个键值对,那么也就不会执行这段操作db的代码了
                    mValues.put(name, value);
                }

settings.db结构如下:

上面示例中指定的TYPE_NOTIFICATION的数据如下(蓝色部分):

最后返回的就是file:///..........这个String数据,再转化成URI返回给调用者

 

OK,那么设置铃声的API, setAc.......执行的过程也类似:

 代码如下 复制代码

public static boolean putString(ContentResolver resolver, String name, String value) {
//这里依然是检查设置的类型是否涉及到系统预置的安全设置集合,如果是,则直接返回false
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Secure, value is unchanged.");
                return false;
            }
//这里执行的是另一个静态内部类NameValueTable中的方法
            return putString(resolver, CONTENT_URI, name, value);
        }

protected static boolean putString(ContentResolver resolver, Uri uri,
                String name, String value) {
            // The database will take care of replacing duplicates.
            try {
                ContentValues values = new ContentValues();
                values.put(NAME, name);
                values.put(VALUE, value);
//指定类型name与相应value插入db的system表中,如果表中已经存在指定的类型字段怎么办? 请看上面的源码注释...
                resolver.insert(uri, values);
                return true;
            } catch (SQLException e) {
                Log.w(TAG, "Can't set key " + name + " in " + uri, e);
                return false;
            }
        }

1,设置铃声之前,要先知道有哪些系统铃声,所以需要扫描,android提供了xxx.media这个contentProvider为此服务,对应的数据库为internal.db/external-xx.db

2,拿到铃声,真正需要设置的时候,提供了Setting类管理这个过程,其对应的数据库为settings.db

  2.1 首先检查是否涉及到系统的一些安全设置参数,这里定义了Secure类来管理,如果涉及到系统安全,那么又分为两种情况:

    2.1.1 如果是查询,则操作secure 表查询

    2.1.2 如果是写操作,则直接return

  2.2 不涉及到系统安全,就属于正常设置,接着定义了System类管理

3,查询操作的实际操作类NameValueCache, 其中定义了

  缓存name/value键值对的集合,避免每次操作都去操作数据库

  可以由调用者指定的uri,便于根据uri决定去操作哪张表

以及写操作的NameValueTable类,因为写操作涉及到id, 所以继承了BaseColumns类

本文章分享一些Android平台中一些免费的UI库及组件资源,有需要的朋友可以下载。

短短数年时间 Android 平台就已经形成了一个庞大而活跃的开发者社区。许多社区开发的项目业已进入成熟阶段,甚至可以用于商业的软件生产中,且不用担心质量问题。
本文编译自 androiduipatterns,意在分享一些免费、开源的 Android UI 库及组件资源。 

 

1. GreenDroid  

 

 

 

该项目可以实现下列的 UI 设计:

  • 动作栏(Action Bar)
  • 快捷动作(Quick Action)
  • 工作区(Workspace)
  • 动态列表(Dynamic List)

以及许多更有用的组件。

项目网站 / ps://market.android.com/details?id=com.cyrilmottier.android.gdcatalog" target="_blank">示例 

 

 

应用程序屏幕截图:

   

 

2. ActionBarSherlock  

 

 

在Google针对手机的动作条API推出前,该项目一直与ICS一起使用。Jake最近将项目拓展到了动作条之外。这里也有针对工作区等的组件。 

 

          项目网站 / 示例  

 

  3. Android Compatibility Package 

 

 

 

  这是一个来自Google Android库的官方扩展。Compatibility Package顾名思义就是Android官方针对旧平台版本所不支持的API或是Android Framework没有提供的函数库,将其打包发布。它包含了许多非常有用的API。该包同样包含工作区UI设计的实现。 

 

 4. iosched  

 

 

 

   这是一个官方的Google I/O的应用(同样可用在GDD,Google Developer Day)(注:Google I/O是Google每年都会举办的历时两天的开发者大会,该大会谈及各种技术问题。开发人员会提供非常多的示例来展示他们的技术。这个项目专门为了这个会议提供了一个Android应用程序。)。该应用程序实现了大量的UI设计,成为Google Android设备拥护者的参考标准。强烈推荐使用该应用程序的仪表盘UI设计模式。(Google代码链接:Dashboard.java) 


  项目网站:http://code.google.com/p/iosched/ 

 

 5. Android-Viewflow 

 

该项目的工作区UI设计模式与Google Docs所使用非常相似。 

项目网站:https://github.com/pakerfeldt/android-viewflow 

6. android-coverflow 

该项目可以用于完成一个cover flow。在这个项目网站的视频中可以得到更多的信息。 

项目网站:http://code.google.com/p/android-coverflow/ 

7. android-viewbadger 

该项目让devs无需修改布局文件(layout file)即可显示badges。 

项目网站:https://github.com/jgilfelt/android-viewbadger  

 

8. android-pulltorefresh 

 

该项目实现动态列表/下拉刷新(pull to refresh)的UI设计。 

项目网站:https://github.com/johannilsson/android-pulltorefresh 

9. Android-ViewPagerIndicator 

该项目可以用于实现工作区的UI设计。 

        项目网站/示例  

本文章分享和下关于android开发之ListView异步加载图片 ,有需了解的朋友可以参考一下。

ListView异步加载图片是非常实用的方法,凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,不用让用户等待下去,下面就说实现方法,先贴上主方法的代码:

 代码如下 复制代码
package cn.wangmeng.test;
 
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
 
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
 
public class AsyncImageLoader {
 
private HashMap<String, SoftReference<Drawable>> imageCache;
 
public AsyncImageLoader() {
imageCache = new HashMap<String, SoftReference<Drawable>>();
}
 
public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
}
};
new Thread() {
@Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}
}.start();
return null;
}
 
public static Drawable loadImageFromUrl(String url) {
URL m;
InputStream i = null;
try {
m = new URL(url);
i = (InputStream) m.getContent();
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
 
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable, String imageUrl);
}
 
}

以上代码是实现异步获取图片的主方法,SoftReference是软引用,是为了更好的为了系统回收变量,重复的URL直接返回已有的资源,实现回调函数,让数据成功后,更新到UI线程。
几个辅助类文件:

 代码如下 复制代码
package cn.wangmeng.test;
 
public class ImageAndText {
private String imageUrl;
private String text;
 
public ImageAndText(String imageUrl, String text) {
this.imageUrl = imageUrl;
this.text = text;
}
public String getImageUrl() {
return imageUrl;
}
public String getText() {
return text;
}
}
package cn.wangmeng.test;
 
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
 
public class ViewCache {
 
private View baseView;
private TextView textView;
private ImageView imageView;
 
public ViewCache(View baseView) {
this.baseView = baseView;
}
 
public TextView getTextView() {
if (textView == null) {
textView = (TextView) baseView.findViewById(R.id.text);
}
return textView;
}
 
public ImageView getImageView() {
if (imageView == null) {
imageView = (ImageView) baseView.findViewById(R.id.image);
}
return imageView;
}
 
}

ViewCache是辅助获取adapter的子元素布局

 代码如下 复制代码
package cn.wangmeng.test;
 
import java.util.List;
 
import cn.wangmeng.test.AsyncImageLoader.ImageCallback;
 
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
 
public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {
 
private ListView listView;
private AsyncImageLoader asyncImageLoader;
 
public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {
super(activity, 0, imageAndTexts);
this.listView = listView;
asyncImageLoader = new AsyncImageLoader();
}
 
public View getView(int position, View convertView, ViewGroup parent) {
Activity activity = (Activity) getContext();
 
// Inflate the views from XML
View rowView = convertView;
ViewCache viewCache;
if (rowView == null) {
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.image_and_text_row, null);
viewCache = new ViewCache(rowView);
rowView.setTag(viewCache);
} else {
viewCache = (ViewCache) rowView.getTag();
}
ImageAndText imageAndText = getItem(position);
 
// Load the image and set it on the ImageView
String imageUrl = imageAndText.getImageUrl();
ImageView imageView = viewCache.getImageView();
imageView.setTag(imageUrl);
Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {
public void imageLoaded(Drawable imageDrawable, String imageUrl) {
ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);
if (imageViewByTag != null) {
imageViewByTag.setImageDrawable(imageDrawable);
}
}
});
if (cachedImage == null) {
imageView.setImageResource(R.drawable.default_image);
}else{
imageView.setImageDrawable(cachedImage);
}
// Set the text on the TextView
TextView textView = viewCache.getTextView();
textView.setText(imageAndText.getText());
 
return rowView;
}
 
}


ImageAndTextListAdapter是实现ListView的Adapter,里面有个技巧就是imageView.setTag(imageUrl),setTag是存储数据的,这样是为了保证在回调函数时,listview去更新自己对应item,大家仔细阅读就知道了。
最后贴出布局文件:

 代码如下 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
 
<ImageView android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
 
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
 
</LinearLayout>
分享一篇关于android调用系统短信Intent时将预填接收号码和内容 ,有需要的朋友可以参考一下下。

前段世界在一个应用中调用系统自带的发送短信的Intent,但是接收者的号码一直穿不过去,代码如下:

 代码如下 复制代码
Uri smsToUri = Uri.parse("smsto:123456");
Intent sendIntent = new Intent(Intent.ACTION_VIEW, smsToUri);
sendIntent.putExtra("sms_body", "Hello dear world");
sendIntent.setType("vnd.android-dir/mms-sms");
startActivity(sendIntent);

然后查到原因是这个Uri格式的无法自动解析出来,需要另外设置下接收者地址,代码如下:

 代码如下 复制代码
sendIntent.putExtra("address", "123456");
[!--infotagslink--]

相关文章

  • Photoshop火龙变冰龙制作教程分享

    今天小编在这里就来给Photoshop的这一款软件的使用者们来说下火龙变冰龙的制作教程,各位想知道具体的制作步骤的使用者们,那么下面就快来跟着小编一起看看制作教程吧。...2016-09-14
  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • Photoshop功夫熊猫电影海报制作步骤分享

    不知不觉功夫熊猫这部电影已经出到3了,今天小编在这里要教大家的是用Photoshop制作功夫熊猫3的海报,各位想知道制作方法的,那么下面就来跟着小编一起看看吧。 给各...2016-09-14
  • Illustrator渐变网格工具绘制可爱的卡通小猪教程分享

    今天小编在这里就来给Illustrator的这一款软件的使用者们来说一说渐变网格工具绘制可爱的卡通小猪的教程,各位想知道具体制作方法的使用者们,那么下面就快来跟着小编一...2016-09-14
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • photoshop日系小清新通透人像调色教程分享

    今天小编在这里就来给photoshop的这一款软件的使用者们来说一说日系小清新通透人像的调色教程,各位想知道具体的调色步骤的使用者们,那么下面就快来跟着小编一起看一看...2016-09-14
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20
  • php威盾解密的例子分享

    下面来给大家分享两个关于php威盾解密的例子,一个是批量解密一个是超级算法的解密都非常的好,大家有举的进入参考。 例子,批量解密 代码如下 复制代码 ...2016-11-25
  • PHP mysql与mysqli事务使用说明 分享

    mysqli封装了诸如事务等一些高级操作,同时封装了DB操作过程中的很多可用的方法。应用比较多的地方是 mysqli的事务。...2013-10-02
  • Android 实现钉钉自动打卡功能

    这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
  • Android 开发之布局细节对比:RTL模式

    下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
  • 微信小程序实现canvas分享朋友圈海报

    这篇文章主要为大家详细介绍了微信小程序实现canvas分享朋友圈海报,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-21