PreferenceFragmentCompat

学习记录中

本来是用PreferenceFragment,发现这东西过期了,提示要用v7下的,然后搜下用哪个包
参考这里:
因为新工程都用的androidx的,所以这个也换成androidx的
迁移到 AndroidX新老库查询
https://blog.csdn.net/qq_26914291/article/details/79917097

androidx.preference:preference:1.0.0

使用

class SettingFragment : PreferenceFragmentCompat() {
    
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

    }

1.简单看下PreferenceFragmentCompat的源码,看下数据的加载过程

private int mLayoutResId = R.layout.preference_list_fragment;//默认布局,下边有

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//省略,就是应用下主题
//然后就是下边这个抽象方法,我们到时候在这里加载xml即可
        onCreatePreferences(savedInstanceState, rootKey);
    }

public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

       //...可以自定义布局,设置divider,divider高度,最后一个item是否添加divider
        mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_android_layout,
                mLayoutResId);

        final Drawable divider = a.getDrawable(
                R.styleable.PreferenceFragmentCompat_android_divider);
        final int dividerHeight = a.getDimensionPixelSize(
                R.styleable.PreferenceFragmentCompat_android_dividerHeight, -1);
        final boolean allowDividerAfterLastItem = a.getBoolean(
                R.styleable.PreferenceFragmentCompat_allowDividerAfterLastItem, true);

//...后边就是加载布局了,获取id是android.R.id.list_container的容器,
//然后是创建RecyclerView

//省略,设置divider的代码

        // If mList isn't present in the view hierarchy, add it. mList is automatically inflated
        // on an Auto device so don't need to add it.
        if (mList.getParent() == null) {
            listContainer.addView(mList);
        }
        mHandler.post(mRequestFocus);

        return view;
    }

//另外还有一些可以用到的方法
//在当前的选项里添加新的
public void addPreferencesFromResource(@XmlRes int preferencesResId) 

//替换新的
public void setPreferencesFromResource(@XmlRes int preferencesResId, @Nullable String key)

默认布局preference_list_fragment.xml
里边一个FrameLayout容器,到时候会add一个RecyclerView进去,然后还有一个empty的textview

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_height="match_parent"
    android:layout_width="match_parent" >

    <FrameLayout
        android:id="@android:id/list_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <TextView android:id="@android:id/empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp"
        android:gravity="center"
        android:visibility="gone" />

</LinearLayout>

2. 开始写xml

系统提供的还不少,一个一个学习


image.png

常用的preference的层级结构

//A container for multiple  {@link Preference} objects
public abstract class PreferenceGroup extends Preference

public final class PreferenceScreen extends PreferenceGroup 
//Used to group {@link Preference} objects and provide a disabled title above  the group.
public class PreferenceCategory extends PreferenceGroup

3.边学边记录

写了个简单的,完事发现没有divider,看源码里有divider啊
仔细看下DividerDecoration的源码
看完发现,要显示divider有两个条件
①非最后一个item的情况,需要同时满足自己isDividerAllowedBelow为true,完事下边紧挨着的那个item的isDividerAllowedAbove为true;
②至于最后一个item,则需要满足isDividerAllowedBelow和mAllowDividerAfterLastItem这两个条件;
这些默认都是false的

        private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
            final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
            final boolean dividerAllowedBelow = holder instanceof PreferenceViewHolder
                    && ((PreferenceViewHolder) holder).isDividerAllowedBelow();
            if (!dividerAllowedBelow) {
                return false;
            }
            boolean nextAllowed = mAllowDividerAfterLastItem;
            int index = parent.indexOfChild(view);
            if (index < parent.getChildCount() - 1) {
                final View nextView = parent.getChildAt(index + 1);
                final RecyclerView.ViewHolder nextHolder = parent.getChildViewHolder(nextView);
                nextAllowed = nextHolder instanceof PreferenceViewHolder
                        && ((PreferenceViewHolder) nextHolder).isDividerAllowedAbove();
            }
            return nextAllowed;
        }

如何修改默认的divider了

看下PreferenceFragmentCompat的默认值哪来的

        getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
        int theme = tv.resourceId;
        if (theme == 0) {
            // Fallback to default theme.
            theme = R.style.PreferenceThemeOverlay;
        }
//我们没有设置主题,默认用的就是PreferenceThemeOverlay这个主题,然后我们去这个fragment所在的包的res下找
        TypedArray a = mStyledContext.obtainStyledAttributes(null,
                R.styleable.PreferenceFragmentCompat,
                R.attr.preferenceFragmentCompatStyle,
                0);

        mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_android_layout,
                mLayoutResId);

        final Drawable divider = a.getDrawable(
                R.styleable.PreferenceFragmentCompat_android_divider);
        final int dividerHeight = a.getDimensionPixelSize(
                R.styleable.PreferenceFragmentCompat_android_dividerHeight, -1);
        final boolean allowDividerAfterLastItem = a.getBoolean(
                R.styleable.PreferenceFragmentCompat_allowDividerAfterLastItem, true);

这是找到的默认的style


image.png

我们可以修改这个,系统的如下

    <style name="PreferenceFragment.Material">
        <item name="android:divider">@drawable/preference_list_divider_material</item>
        <item name="allowDividerAfterLastItem">false</item>
    </style>

修改后的,放到我们app的style.xml下即可

    <style name="PreferenceFragment.Material" tools:override="true">
        <item name="android:divider">@drawable/divider_normal_gray</item>
        <item name="android:dividerHeight">5dp</item>
        <item name="allowDividerAfterLastItem">true</item>
    </style>

当然了,这里也可以修改fragment默认加载的布局,不过里边必须有一个id如下的ViewGroup,
还可以有个id是recycler_view的RecyclerView,没有的话代码里会add一个进去

    <FrameLayout
        android:id="@android:id/list_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

PreferenceCategory

image.png

category的title颜色,默认使用的是colorAccent
当然,这些都是可以改的,你可以修改默认的布局,修改默认布局里TextView的style


image.png
    <androidx.preference.PreferenceCategory android:title="category">
        <androidx.preference.PreferenceScreen
            android:icon="@drawable/settings_general"
            android:title="test1"
            app:layout="@layout/view_settings_list_item">
            <androidx.preference.CheckBoxPreference
                android:icon="@drawable/i_settings_wifi_0"
                android:key="wifiauto"
                android:title="auto" />
            <androidx.preference.SwitchPreference
                android:icon="@drawable/i_settings_wifi_4"
                android:key="wifi111"
                android:title="wifi" />
        </androidx.preference.PreferenceScreen>
    </androidx.preference.PreferenceCategory>

ListPreference

单选弹框

    <androidx.preference.ListPreference
        android:entries="@array/ID_SETTING_MENU_ARRAY"
        android:entryValues="@array/ID_SETTING_MENU_ARRAY_VALUE"
        android:defaultValue="0"
        android:title="single choice"
        android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT2"/>

系统没有提供页面内的单选功能,只有这种弹框,如果需要的话得自定义了
比如需要这种页面内的单选


image.png

系统有checkbox的preference,没有radiobutton的,我们可以稍微修改下
看下checkbox的style,最右边的widget替换的是个checkbox

    <style name="Preference.CheckBoxPreference">
        <item name="android:widgetLayout">@layout/preference_widget_checkbox</item>
    </style>

而CheckBoxPreference 里并没有强求是checkbox,判断的都是Checkable,而radioButton也有这属性

public class CheckBoxPreference extends TwoStatePreference

    private void syncCheckboxView(View view) {
        if (view instanceof CompoundButton) {
            ((CompoundButton) view).setOnCheckedChangeListener(null);
        }
        if (view instanceof Checkable) {
            ((Checkable) view).setChecked(mChecked);
        }
        if (view instanceof CompoundButton) {
            ((CompoundButton) view).setOnCheckedChangeListener(mListener);
        }
    }

如下简单修改即可

        <androidx.preference.CheckBoxPreference
            android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT"
            app:widgetLayout="@layout/preference_widget_radiobutton"
            android:title="@string/ID_SETTINGS_MENU_LAYOUT_TILE"/>

//preference_widget_radiobutton布局如下,原本是个CheckBox,我们这里替换成RadioButton
<?xml version="1.0" encoding="utf-8"?>
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/checkbox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:focusable="false"
    android:clickable="false"
    android:background="@null" />

替换完发现没啥太大意义,这玩意和radioButton有区别,这个可以取消选择,RadioButton选中的再点还是选中状态

自定义单选功能

我们自定义一下页面内单选功能,用同一个key,给个默认的value

    <androidx.preference.PreferenceScreen
        android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT"
        android:title="@string/ID_SETTINGS_MENU_LAYOUT"
        android:layout="@layout/view_settings_list_item"
        android:summary="">
        <com.xxx.demo0327.setting.RadioButtonPreference
            android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT"
            app:widgetLayout="@layout/preference_widget_radiobutton"
            android:icon="@drawable/settings_general"
            app:defaultValue="0"
            android:title="@string/ID_SETTINGS_MENU_LAYOUT_SIDE"/>
        <com.xxx.demo0327.setting.RadioButtonPreference
            android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT"
            app:defaultValue="1"
            app:widgetLayout="@layout/preference_widget_radiobutton"
            android:title="@string/ID_SETTINGS_MENU_LAYOUT_TILE"/>
    </androidx.preference.PreferenceScreen>

代码

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;


public class RadioButtonPreference extends Preference implements SharedPreferences.OnSharedPreferenceChangeListener{

    public RadioButtonPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override//给每个选项设置一个defaultValue,用来判断选中的是哪个
    protected String onGetDefaultValue(TypedArray a, int index) {
        value=a.getString(index);
        return value;
    }

    private String value; 

    public String getValue(){
      return   getPreferenceManager().getSharedPreferences().getString(getKey(),"0");
    }
    public void saveValue(){
        getPreferenceManager().getSharedPreferences().edit().putString(getKey(),value).commit();
    }

    @Override
    public void onAttached() {
        super.onAttached();
        getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onDetached() {
        super.onDetached();
        getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    }
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {

        if (TextUtils.equals(getKey(),key)&&view!=null&&view instanceof Checkable) {
            ((Checkable) view).setChecked(TextUtils.equals(getValue(),value));
        }
//单选的preference大家的key都一样,所以监听下改变,修改自己的radioButton的状态即可
    }
    @Override
    protected void onClick() {
        super.onClick();//点击的时候还继续是选中状态
        saveValue();
        if (view!=null&&view instanceof Checkable) {
            ((Checkable) view).setChecked(true);
        }
    }
    View view;
    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);
         view=holder.findViewById(android.R.id.checkbox);
        if (view instanceof Checkable) {
            ((Checkable) view).setChecked(TextUtils.equals(getValue(),value));
        }
    }

}

这里点击以后页面不消失的,如果你点击以后想退回上个页面,那么在fragment里处理即可,
如下每个preference点击都会走这里,可以判断下然后做处理

override fun onPreferenceTreeClick(preference: Preference?): Boolean 

前边的icon不设置,在pad上也占位的问题

新的这种preference,前边的icon,就算不设置它也会占位的,代码如下

            if (mIcon != null) {
                imageView.setVisibility(View.VISIBLE);
            } else {
                imageView.setVisibility(mIconSpaceReserved ? View.INVISIBLE : View.GONE);
            }

查下默认值iconSpaceReserved在pad上默认是true,我测试机就是pad
你可以在自定义style里改,也可以在xml里改

    <style name="Preference.Material">
        <item name="android:layout">@layout/preference_material</item>
        <item name="allowDividerAbove">false</item>
        <item name="allowDividerBelow">true</item>
        <item name="singleLineTitle">false</item>
        <item name="iconSpaceReserved">@bool/config_materialPreferenceIconSpaceReserved</item>
    </style>
image.png

暂时不研究这个了,先把已有的代码贴下

class SettingFragment : PreferenceFragmentCompat() ,SharedPreferences.OnSharedPreferenceChangeListener{


    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
//加载xml文件
        addPreferencesFromResource(R.xml.setting_preference)
    }

    override fun onResume() {
        super.onResume()
        preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
    }

    override fun onPause() {
        super.onPause()
        preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
    }

    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
        println("change==========$key=====${findPreference(getString(R.string.ID_SETTINGS_KEY_MENU_LAYOUT)).title}")
        if(TextUtils.equals(key,getString(R.string.ID_SETTINGS_KEY_MENU_LAYOUT))){    findPreference(getString(R.string.ID_SETTINGS_KEY_MENU_LAYOUT)).setSummary(sharedPreferences.getString(key,"-1"))
        }
    }

    override fun onPreferenceTreeClick(preference: Preference?): Boolean {
        val result=super.onPreferenceTreeClick(preference);
        println("onPreferenceTreeClick====$result==========$preference")

        return result
    }
//对于Preference下边有子元素的,点击的时候会走这里,然后我们就可以设置跳转【其实就是加载新的preference】
    override fun onNavigateToScreen(preferenceScreen: PreferenceScreen?) {

        super.onNavigateToScreen(preferenceScreen)
        println("onNavigateToScreen============$preferenceScreen====${preferenceScreen?.preferenceCount}")
        setPreferenceScreen(preferenceScreen)
        (activity as SettingActivity).changeTitle(preferenceScreen?.title?:"")//修改acitivity的标题
    }

//activity的onbackPress调用这个方法判断是否需要关闭页面
    fun handledBack():Boolean{
        println("handledBack==================${preferenceScreen.parent}")
        return handleParent(preferenceScreen.parent)
    }

//根据当前展示的preference,判断parent是否是PreferenceScreen,是的话展示parent
    fun handleParent(preferenceGroup: PreferenceGroup?):Boolean{
        if(preferenceGroup==null) return false
        if(preferenceGroup is PreferenceScreen){
            preferenceScreen=preferenceGroup;
            (activity as SettingActivity).changeTitle(preferenceScreen?.title?:"")
            return true;
        }
        if(preferenceGroup is PreferenceCategory){
           return handleParent(preferenceGroup.parent)
        }
        return false;
    }
}

xml文件,主要就写了第一个,下边还有2层可以点,其他几个没写

<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:title="@string/ID_SETTINGS_TITLE">

<androidx.preference.PreferenceScreen
    android:title="@string/ID_SETTINGS_GENERAL"
    android:layout="@layout/view_settings_list_item"
    app:allowDividerBelow="true"
    android:icon="@drawable/settings_general">
    <!--Audio-->
    <androidx.preference.PreferenceScreen
        android:title="@string/ID_SETTINGS_AUDIO"
        app:iconSpaceReserved="false"
        android:layout="@layout/view_settings_list_item">
        <androidx.preference.SeekBarPreference
            android:key="@string/ID_SETTINGS_KEY_VOLUME"
            android:title="@string/ID_SETTINGS_AUDIO_VOLUME"/>
        <androidx.preference.SwitchPreference
            android:key="@string/ID_SETTINGS_KEY_TOUCH_AUDIO"
            android:title="@string/ID_SETTINGS_AUDIO_TOUCH_AUDIO"/>
    </androidx.preference.PreferenceScreen>


    <!--Menu layout-->
    <androidx.preference.PreferenceScreen
        android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT"
        android:title="@string/ID_SETTINGS_MENU_LAYOUT"
        android:layout="@layout/view_settings_list_item"
        android:summary="">
        <com.charliesong.demo0327.setting.RadioButtonPreference
            android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT"
            app:widgetLayout="@layout/preference_widget_radiobutton"
            android:icon="@drawable/settings_general"
            app:defaultValue="0"
            android:title="@string/ID_SETTINGS_MENU_LAYOUT_SIDE"/>
        <com.charliesong.demo0327.setting.RadioButtonPreference
            android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT"
            app:defaultValue="1"
            app:widgetLayout="@layout/preference_widget_radiobutton"
            android:title="@string/ID_SETTINGS_MENU_LAYOUT_TILE"/>
    </androidx.preference.PreferenceScreen>
    <androidx.preference.ListPreference
        android:entries="@array/ID_SETTING_MENU_ARRAY"
        android:entryValues="@array/ID_SETTING_MENU_ARRAY_VALUE"
        android:defaultValue="0"
        android:title="single choice"
        android:key="@string/ID_SETTINGS_KEY_MENU_LAYOUT2"/>

    <androidx.preference.PreferenceCategory android:title="category">
        <androidx.preference.PreferenceScreen
            android:icon="@drawable/settings_general"
            android:title="test1"
            app:layout="@layout/view_settings_list_item">
            <androidx.preference.CheckBoxPreference
                android:icon="@drawable/i_settings_wifi_0"
                android:key="wifiauto"
                android:title="auto" />
            <androidx.preference.SwitchPreference
                android:icon="@drawable/i_settings_wifi_4"
                android:key="wifi111"
                android:title="wifi" />
        </androidx.preference.PreferenceScreen>
    </androidx.preference.PreferenceCategory>
</androidx.preference.PreferenceScreen>


    <androidx.preference.PreferenceScreen
        android:title="@string/ID_SETTINGS_MAPS"
        app:allowDividerAbove="true"
        android:layout="@layout/view_settings_list_item"
        android:icon="@drawable/settings_maps">

    </androidx.preference.PreferenceScreen>


</androidx.preference.PreferenceScreen>

xml里Preference的显示顺序

有这样一个布局,那个my_device_info_header 根据order的不同,显示的位置也不同,这个逻辑到底是啥样的。其他两个PreferenceCategory没有设置order。
第一个Preference设置order为负值,它就显示在第一个位置,
如果order为0,那么显示在第二个位置,
为1显示在第三个位置

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:key="my_device_info_pref_screen"
    android:title="about_settings">

    <Preference
        android:key="my_device_info_header"
        android:layout="@layout/settings_entity_header"
        android:order="0"
        android:selectable="false" />

    <PreferenceCategory
        android:key="basic_info_category"
        android:selectable="false"
        android:title="my_device_info_basic_info_category_title">
    </PreferenceCategory>
    <PreferenceCategory android:title="my_device_info_legal_category_title">
    </PreferenceCategory>

首先默认的order如下,在Preference类里

    public static final int DEFAULT_ORDER = Integer.MAX_VALUE;
    private int mOrder = DEFAULT_ORDER;

    public int getOrder() {
        return mOrder;
    }
//排序的话,先比较order,一样的话再看title
    public int compareTo(@NonNull Preference another) {
        if (mOrder != another.mOrder) {
            // Do order comparison
            return mOrder - another.mOrder;
        } else if (mTitle == another.mTitle) {
            // If titles are null or share same object comparison
            return 0;
        } else if (mTitle == null) {
            return 1;
        } else if (another.mTitle == null) {
            return -1;
        } else {
            // Do name comparison
            return mTitle.toString().compareToIgnoreCase(another.mTitle.toString());
        }
    }

查下哪里用到这个getOrder,在PreferenceGroup类里

    public boolean addPreference(@NonNull Preference preference) {
        if (mPreferences.contains(preference)) {
            return true;
        }
//...

        if (preference.getOrder() == DEFAULT_ORDER) {
            if (mOrderingAsAdded) {//这个默认是true,除非你在xml里设置
                preference.setOrder(mCurrentPreferenceOrder++);//默认是0
            }
//...
        }

        int insertionIndex = Collections.binarySearch(mPreferences, preference);
        if (insertionIndex < 0) {
            insertionIndex = insertionIndex * -1 - 1;
        }
        synchronized (this) {
            mPreferences.add(insertionIndex, preference);
        }

分析上边的代码,可以看到集合数据mPreferences的插入顺序,主要看索引insertionIndex。
如果preference有设置order的话,那就用自己的order,如果没有设置的话,那么按照顺序设置order(从0开始增加,这里主要看binarySearch这个方法了。

    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            return Collections.iteratorBinarySearch(list, key);
    }

    private static <T>
    int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
        int low = 0;
        int high = list.size()-1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            Comparable<? super T> midVal = list.get(mid);
            int cmp = midVal.compareTo(key);

            if (cmp < 0)
                low = mid + 1;
            else if (cmp > 0)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found
    }

这里举例说明:
第一个Preference的order是0,后边两个没设置order,按照代码里的逻辑,会自动为order赋值为0和1. xml里的顺序为 A(0),B(0),C(1) ,括弧里为order的值,ABC分别表示xml里的3个Preference。
解析第一个A(0), 集合长度为0,所以low=0,high=-1,while不满足,返回-1 ,根据

        if (insertionIndex < 0) {
            insertionIndex = insertionIndex * -1 - 1;
        }

所以A的insertionIndex 为-1*-1-1也就是0.
此时集合里数据为 [A0]
解析第二个B(0), 集合长度为1,所以low=0,high=0,mid=0, mid取出来的就是A0,根据比较规则,因为A0的title为null,所以cmp=1,high为-1,跳出循环,返回-1.同上B的insertionIndex 为0.所以B0插入在A0前边。
此时集合里的数据为 [B0,A0]
解析第三个C1,集合长度为2,所以low=0,high=1,mid=0,mid取出来的就是B0,根据比较规则,cmp为-1,所以low变为1,mid也成了1,取出的值为A0,和C1比较,cmp为-1,此时low变为2.跳出循环,返回-3,根据if条件,insertionIndex最终为2.
此时集合里的数据为 [B0,A0,C1]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容

  • 我妈妈年轻的时候就喜欢看小说,特别是琼瑶阿姨的书,我也受到妈妈的影响,从小学就开始看小说,其中最先读到的就是家里面...
    汐堇年阅读 243评论 0 2
  • 前言 前段时间在泡网上看到这个文章传送门,对于客户端开发而言,实现各种奇奇怪怪的UI效果也是常态,动画更是点睛之笔...
    狸小华阅读 5,328评论 6 11
  • 我们虽然都生活在同一个城市,但却过着截然不同的生活。遇见你,我才知道什么是青春。
    旻子826阅读 154评论 0 0
  • 雨,滴滴答答地掉落在青瓦沿上,高高低低的回响。透过古旧的窗格望出去,斑驳的白墙落寞的伫立在雨里,寂静无语。 宏村,...
    余葉子阅读 562评论 10 17
  • 咏荆轲(其一) 卫客报强秦,吴钩三尺寒。 狗屠筑前横,和泣正酒酣。 燕丹奉宾客,当保金瓯全。 侠者如曹...
    灼灼新桃阅读 220评论 0 1