Problem z Fragmentem i klawiaturą

Problem z Fragmentem i klawiaturą
CH
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 miesiące
  • Postów:128
0

Witam.

Stosunkowo niedawno rozpocząłem programowanie na Androida. Obecnie próbuję napisać swoją prostą aplikację (aha, piszę jeszcze niestety w Javie jak coś). Moja aplikacja działa w taki sposób, żę mam jakby gówną aktywność, w której dynamicznie podmieniam fragmenty (FragmentManager i te sprawy). Problem pojawił się w momencie, w którym jeden z fragmentów ma EditText'y no i jak wyświetla się klawiatura - to pod warunkiem, że użytkownik nie naciśnie "done" - gdy przejdzie do innego fragmentu (podmienie fragment) klawiatura się nie zamyka, zasłaniająć część innego fragmentu. Moje pytanie brzmi - jak powinno się to zrobić, żeby klawiatura zamykała się przy przejściu do innego fragmentu, a otwierała (pod warunkiem że była otwarta przy zamknięciu) po powrocie do tego fragmentu (a i klawisz "done" znika też przy przejściu do innego fragmentu - ale dodanie go (co bym chyba potrafił) nic nie zmieni)?

Ogólnie myślałem o metodach onStop i onResume ale nie jest to chyba dobre wyjście.

Pomoże ktoś, bo moje doświadczenie jest aktualnie dosyć nikłe?

Poniższy kod jest z pewnością daleki od doskonałości (i optymalności) ale mam nadzieję, że ktoś zdoła mi trochę pomóc. A i KONSTRUKTYWNĄ krytykę odnośnie kodu też lubię. ;)

Z góry dzięki.

Poniżej XML z layoutem tego fragmentu (chyba tutaj nie potrzebny bo trzeba to zrobić kodem?)

Kopiuj
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TextInputLayout
        android:id="@+id/frameLayout"
        android:layout_width="210dp"
        android:layout_height="40dp"
        android:layout_alignLeft="@+id/pic_preview"
        android:layout_alignStart="@+id/pic_preview"
        android:layout_below="@+id/frameLayout2"
        android:layout_marginLeft="49dp"
        android:layout_marginStart="49dp"
        android:layout_marginTop="36dp">

        <EditText
            android:id="@+id/edit_text_name"
            android:layout_width="@dimen/edit_text_width"
            android:layout_height="@dimen/edit_text_height"
            android:layout_marginBottom="35dp"
            android:hint="@string/not_working"
            android:imeOptions="actionDone"
            android:inputType="text"/>
    </android.support.design.widget.TextInputLayout>

    <android.support.design.widget.TextInputLayout
        android:id="@+id/frameLayout2"
        android:layout_width="210dp"
        android:layout_height="40dp"
        android:layout_alignLeft="@+id/frameLayout"
        android:layout_alignParentTop="true"
        android:layout_alignStart="@+id/frameLayout"
        android:layout_marginTop="35dp">

        <EditText
            android:id="@+id/editText"
            android:layout_width="@dimen/edit_text_width"
            android:layout_height="@dimen/edit_text_height"
            android:layout_marginBottom="65dp"
            android:hint="@string/hint_name"
            android:paddingTop="5dp"
            android:imeOptions="actionDone"
            android:inputType="text"/>

    </android.support.design.widget.TextInputLayout>

    <ImageView
        android:id="@+id/pic_preview"
        android:layout_width="110dp"
        android:layout_height="110dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:src="@drawable/android"
        android:layout_marginLeft="22dp"
        android:layout_marginStart="22dp" />

    <Button
        android:id="@+id/chose_pic"
        android:layout_width="110dp"
        android:layout_height="45dp"
        android:layout_alignLeft="@+id/pic_preview"
        android:layout_alignStart="@+id/pic_preview"
        android:layout_below="@+id/pic_preview"
        android:layout_toLeftOf="@id/chose_pic"
        android:layout_marginTop="13dp" />



</RelativeLayout>
Kopiuj

public class PicsChooserFrag extends Fragment {

    private boolean keyboard_on;

   
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle){
        RelativeLayout relative=(RelativeLayout)inflater.inflate(R.layout.image_chooser,viewGroup,false);
        return relative;
    }
//????????????????????????????????????????
    public PicsChooserFrag(){
        super();
        keyboard_on=false;
    }

    //onStop - when user doesn't see the fragment any more
    //onREsume - when user see the fragment  once more

    @Override
    public void onStop(){
        super.onStop();

    }

    @Override
    public void onResume(){
        super.onResume();
    }




}
Kopiuj
public class MainActivity extends AppCompatActivity {

    // ListView representing options in the drawer
    private ListView listViewOfDrawer;
    // reference to whole DrawerLayout containing ToolBar, mainFragment and ListView with drawer options
    private DrawerLayout wholeDrawer;
    private String[]titles; // array representing string shown in drawer
    //ActionBarDrawerToggler provides a handy way to tie together the funcionallyty of DrawerLAyout and the framework ActionBar
    //  "makes the hamburger work"
    private ActionBarDrawerToggle drawerToggle;

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

        titles=getResources().getStringArray(R.array.title);

        //operations concerning ListView with options of drawer
        listViewOfDrawer=(ListView)findViewById(R.id.drawer_list_view);
        //setting sample content of Drawer using ArrayAdapter
        listViewOfDrawer.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_activated_1,titles));
        //adding listview listener to the ListView representing "drawer" options
        listViewOfDrawer.setOnItemClickListener(new DrawerClickListener());

      
        wholeDrawer=(DrawerLayout)findViewById(R.id.drawerLayout);


  
        getFragmentManager().addOnBackStackChangedListener(
                new FragmentManager.OnBackStackChangedListener(){
                    public void onBackStackChanged(){
                      FragmentManager fragmentManager=getFragmentManager();
                      Fragment fragment=fragmentManager.findFragmentByTag("fragment");

                        if(fragment instanceof PicsFragment ){
                            // actions when PicsFragment was added
                            Toast.makeText(getBaseContext(),"PicsFragment",Toast.LENGTH_SHORT).show();//getBaseContext ???

                        }else if(fragment instanceof PicsChooserFrag){
                            Toast.makeText(getBaseContext(),"PicsChooserFrag",Toast.LENGTH_SHORT).show();//getBaseContext ???

                        }

                    }
                }
        );




       
       Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);
        //displaying hamburger button
        getSupportActionBar().setHomeButtonEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);




        // making the hamburger work
        drawerToggle=new ActionBarDrawerToggle(this,wholeDrawer,R.string.app_name,R.string.app_name){

            @Override
            public void onDrawerClosed(View drawerView){
              //  Toast.makeText(getApplicationContext(),"Zamknieto Menu",Toast.LENGTH_SHORT).show();
                super.onDrawerClosed(drawerView);
                invalidateOptionsMenu();
            }

            @Override
            public void onDrawerOpened(View drawerView){
              //  Toast.makeText(getApplicationContext(),"Otworzono Menu",Toast.LENGTH_SHORT).show();
                invalidateOptionsMenu();//declare that options menu has changed , so should be redeclared
            }

        };


        wholeDrawer.addDrawerListener(drawerToggle);
        drawerToggle.syncState();




    }

    // implementation of "OnItemClickListViewListener" interface
    private class DrawerClickListener implements ListView.OnItemClickListener{

        @Override
        public void onItemClick(AdapterView<?> praent,View view, int position,long id){

            selectItem(position);
        }
    }

    private void selectItem(int position){
        Fragment fragmentToPut=null;
        switch(position){
            case 0:
                fragmentToPut=new PicsFragment();
                break;
            case 1:
                fragmentToPut=new PicsChooserFrag();
                Toast.makeText(this,"Choosing...", Toast.LENGTH_LONG).show();
                break;
            default:
               
                fragmentToPut=new PicsFragment();// default
                Toast.makeText(this,"Option doesn't work yet :(",Toast.LENGTH_SHORT).show();
        }
        //we replace the fragment ...
        FragmentTransaction fragTran=getFragmentManager().beginTransaction();
        fragTran.replace(R.id.main_fragment,fragmentToPut,"fragment");
        fragTran.addToBackStack(null);
        //selects standard transaction animation for this transaction
        fragTran.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        fragTran.commit();
        //we close the drawer
        wholeDrawer.closeDrawer(listViewOfDrawer,false);
    }


    // this method places menu options to menu
    //called only once, the first time the options menu is created
    @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) {
       
        int id = item.getItemId();
   
        if (id == R.id.action_settings) {
            Toast.makeText(this,"Options",Toast.LENGTH_SHORT).show();

        



        }else if(id == R.id.author){
            Toast.makeText(this,"Author",Toast.LENGTH_SHORT).show();
        }else{
            //showing menu
            Toast.makeText(this,"Menu",Toast.LENGTH_SHORT).show();
            wholeDrawer.openDrawer(Gravity.START);
        }

        return super.onOptionsItemSelected(item);
    }


  
    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        
        drawerToggle.syncState();
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }





}

1

co do chowania klawiatury to zobacz tutaj
https://stackoverflow.com/questions/1109022/close-hide-the-android-soft-keyboard
zrob sobie z tego metode statyczna w jakiejs klasie np. ViewUtils

co do otwierania klawy jak ktos wroci do fragmentu na ktorym juz byl to trudniejsza sprawa, sprawdze jutro Twoj kod bo dzisiaj juz nie mam czasu

CH
dobra, dzięki ;) jak coś wymyślę to najwyżej dopiszę zmieniony kod ;) ale nie wiem, bo jak mówię to początki ;))
CH
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 miesiące
  • Postów:128
0

Dobra, już wczoraj nie zdążyłem odpowiedzieć.

Otóż stowrzyłem sobie tą klasę "narzędziową" (nie wklejam bo to jest to co na Stacku) i w klasie PicsChooserFrag dałem ją w metodzie onPause:

Kopiuj
@Override
    public void onPause(){
        super.onPause();
        
        ViewUtils.hideKeyBoard(getActivity());


    }


w sumie prawie działa ale problemem jest teraz to, że jak pojawi się klawiatura i otworzę szufladę (żeby włączyć inny fragment) to ta klawiatura zasłania połowę tej szulfady (gdzie potencjalnie mogą być jakieś opcje)...
Pomyslałem więc o metodzie onDrawerOpened ActionBarDrawerToggle'ra (bo chyba zamykanie ewentualnie zamkniętej klawiatury nie będzie problemem - przynajmniej teoretycznie bo chyba nie jest to dobre dla optymalizacji) tylko jak tam przekazać aktywność? :( a może da się jakoś inaczej? Ponieżej fragment kodu z MainActivity, gdzie chciałbym to wstawić:

Kopiuj
  // making the hamburger work
        drawerToggle=new ActionBarDrawerToggle(this,wholeDrawer,R.string.app_name,R.string.app_name){

            @Override
            public void onDrawerClosed(View drawerView){
              //  Toast.makeText(getApplicationContext(),"Zamknieto Menu",Toast.LENGTH_SHORT).show();
                super.onDrawerClosed(drawerView);
                invalidateOptionsMenu();
            }

            @Override
            public void onDrawerOpened(View drawerView){
              //  Toast.makeText(getApplicationContext(),"Otworzono Menu",Toast.LENGTH_SHORT).show();
                invalidateOptionsMenu();//declare that options menu has changed , so should be redeclared


                //TODO tutaj chciałbym wstawić ten kod zamykający klawiaturę



            }

        };

a co do otwierania, pod warunkiem, że była otwarta, to jeszcze nic nie wymyśliłem chyba ale ostatecznie nie jest to takie ważne - chciaż jak ktoś ma jakiś pomysł... ;)

Pozdrawiam i dzięki za wszelkie wskazówki.

1
Chungu napisał(a):

tylko jak tam przekazać aktywność? :
Pozdrawiam i dzięki za wszelkie wskazówki.

A to nie działa?

Kopiuj
ViewUtils.hideKeyBoard(MainActivity.this);
CH
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 miesiące
  • Postów:128
0

Ok, dzięki działa. ;) Zapomniałem o tym "kwalifikowanym" this :) A wie ktoś może czy updatowanie bazy danych z Fragmentu to dobry pomysł, czy lepiej uruchomić wątek (chyba ASyncTask coś takiego) w MainActivity (a i próbuję użyć ContentProvidera - jeszcze nie wiem jak to połączę ale mam neta i książki ;)) ) - na razie chodzi mi tylko o to czy update z Fragmentu ma jakikolwiek sens i jest "dobrą" praktyką?

Ogólnie mam trochę problem z wykorzystaniem teoretycznej wiedzy w praktyce więc wszelkie wskazówki będę doceniał. :)
Pozdrawiam.

0

To już lepiej załóż nowy wątek z nowym pytaniem, skoro ten oznaczyłeś jako rozwiązany, nie pytaj dalej o coś całkiem innego

1

ContentProvider to zlo... ktos kto to wymyslil powinien za to beknac.

uzyj normalnie SqlLite'a. a co do watkow, idealnie jezeli MainThread (UIThread) powinienes uzywac tylko do aktualizowania widoku (aktywnosc, fragment, view etc)
co sie da powinienes robic w osobnycn watkach.

dobrze sie zarzadza watkami przez RxJava + RxAndroid + Schedulery,
ale naucz sie podstaw Androida na Rx jeszcze przyjdzie czas

0

Ten kto to wymyślił, wie do czego to służy. Ty jak widać nie wiesz.

CH
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 miesiące
  • Postów:128
0

UPDATE: dobra coś znalazłem ale jak ktośchciałby pomóc, to zapraszam. :)

Hm, z fragmentów które czytałem (no i z samej nazwy) wywnioskowałem, żę jest to jakby pośrednik między danymi (np. z BD) a aktywnością no i że można do tego ContentProvidera sięgać też z innych apek (a tym samym do samej BD) jakby w sposób ustandaryzowany, no to chyba lepiej żebym tym robił? :/ Problem jest tego typu, że już (przy drobnej pomocy książki) to zaimplementowałem no i teraz mam problem jak się tym posługiwać (czy wystarczy stworzyć tylko obiekt tego providera i normalnie wywoływać jego metody typu update z odpowiednim Uri???)

Poniżej wstawiam sam kod mojego ContentProvidera (i fragment kodu z DatabaseHlepra tworzącego baze; DataBaseDescription zawiera opis bazy np. nazwy kolumn...)? mógłby ktoś pomóc mi (nie wiem może być jakaś lista kroków/linki do artykułów coś takiego... jak się dostać i zapisać np. obrazek w tej bazie?)

Kopiuj
public class GalleryDataBaseContentProvider extends ContentProvider {

    // in order to get access to the db
    private GalleryDatabaseHelper dbHelper;
    private String errorMessage;

    // UriMatcher - usefulclass when writting ContentProvider - it helps to
    //recognize requests
    private static final UriMatcher uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);

    // consts used to recognize the operation
    private static final int ONE_PIC=1;//operation concerning only 1 pic
    private static final int WHOLE_TABLE=2;//operation on the whole table

    // static block configurating UriMAtcher object
    //static block is being called only one when the class is initialized/loaded
    static{
       

        //generally we build up the tree of queries ??
        // Uri address of only one pic - tablename/number
        uriMatcher.addURI(DatabaseDescription.AUTHORITY,DatabaseDescription.Picture.TABLE_NAME_+"/#",ONE_PIC);
        //Uri address of the whole table -  tablename
        uriMatcher.addURI(DatabaseDescription.AUTHORITY,DatabaseDescription.Picture.TABLE_NAME_,WHOLE_TABLE);
    }


    @Override
    public boolean onCreate() {
        dbHelper=new GalleryDatabaseHelper(getContext());
        errorMessage=getContext().getString(R.string.unsupportedQuery);
        return true;
    }


    // this method is not required in this app - return null
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }



 

    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {

        //SQLiteQueryBuilder helps us to build a query
        SQLiteQueryBuilder queryBuilder=new SQLiteQueryBuilder();
        // this builder is concerning our pics table
        queryBuilder.setTables(DatabaseDescription.Picture.TABLE_NAME_);

        // we try to match the uri
        switch(uriMatcher.match(uri)){
            case ONE_PIC:
                // SQL with WHERE clause (where id=id_from_passed_uri)
                queryBuilder.appendWhere(DatabaseDescription.Picture.TABLE_NAME_+"="+uri.getLastPathSegment());

                break;
            case WHOLE_TABLE: // we chose whole table...

                break;
            default:
                unsupportedOperation();
        }


     
        Cursor cursor=queryBuilder.query(dbHelper.getReadableDatabase(),projection,selection,selectionArgs,null,null,sortOrder);

        
        cursor.setNotificationUri(getContext().getContentResolver(),uri);

        return cursor;
    }


    private void unsupportedOperation(){
        // informing with helpful Toast
        Toast.makeText(getContext(),errorMessage,Toast.LENGTH_SHORT).show();
        // we indicate unsupportedoperation by throwing appropriate exception
        throw new UnsupportedOperationException(errorMessage);

    }


    //save new Pic to database
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {

        Uri newPicUri=null;

        switch(uriMatcher.match(uri)){
            case WHOLE_TABLE:

                // insert new pic to database
                long insRowId=dbHelper.getWritableDatabase().insert(DatabaseDescription.Picture.TABLE_NAME_,null,contentValues);

                // create Uri address if success
                //else throw an exception
                if(insRowId>0){ // SQLite rows starts at 1
                    // we create new Pic Uri...
                    newPicUri=DatabaseDescription.Picture.createUri(insRowId);


                     // notify listeners that database was modified
                    getContext().getContentResolver().notifyChange(uri,null);
                }else{
                    throw new SQLException(getContext().getString(R.string.insert_failure));
                }

                break;
            default:
                unsupportedOperation();
        }


        return  newPicUri;


    }

    // TODO implement delete method !!!
    @Override
    public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
        return 0;
    }


    //update previously saved pic
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {

        int numbersOfRowsUpdated=0; // to check if the update was successful

        switch(uriMatcher.match(uri)){
            case ONE_PIC:
                    numbersOfRowsUpdated=dbHelper.getWritableDatabase().update(DatabaseDescription.Picture.TABLE_NAME_,contentValues,DatabaseDescription.Picture._ID+"="+uri.getLastPathSegment(),strings);
                break;
            default:
                unsupportedOperation();
        }


        // if sth was updated we should notifychange
        if(numbersOfRowsUpdated>0){
            getContext().getContentResolver().notifyChange(uri,null);
        }

        return numbersOfRowsUpdated;
    }
}

"SQL CREATE TABLE":

Kopiuj
@Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        //SQL creating appropriate table
        final String CREATE_TABLE_SQL_="CREATE_TABLE "+ DatabaseDescription.Picture.TABLE_NAME_+" ("+
                DatabaseDescription.Picture._ID+" integer primary key, "+
                DatabaseDescription.Picture.COLUMN_PIC_NAME+" TEXT, "+
                DatabaseDescription.Picture.COLUMN_PIC_+ " BLOB);";

        sqLiteDatabase.execSQL(CREATE_TABLE_SQL_);


    }

Dzięki ;)

edytowany 1x, ostatnio: Chungu
1

W skrócie: jeśli potrzebujesz żeby inne apki mogły sięgać do tych danych, które masz w swojej apce, to potrzebujesz ContentProvidera (zresztą sama jego nazwa chyba wskazuje na przeznaczenie, tak?). A jesli nie potrzebujesz, to sqlite. A jeżeli masz naprawdę mało danych do zapisania i ich struktura jest prosta, to nie potrzebujesz nawet sqlite, wystarczy ci SharedPreferences, który serializuje dane do xml i trzyma w plikach xml.

1

P.S. nie wiem co chcesz konkretnie zrobić, ale jeśli zamierzasz wpychać zdjęcia jako bloby do bazy, to wiedz że jest to złe.

CH
Taki sposób znalazłem na Stacku, to ma być jakby apka, ktora imituje galerię do przeglądania zdjęć... to jak w takim razie najlepiej by to zrobić? Bo wpychanie do drawable to chyba nie wchodzi w grę? :/
1

Najpierw powiedz, o co ci konkretnie chodzi. Jeśli są to obrazy statyczne, tzn użytkownik nie będzie wgrywał np nowych obrazów, które mają potem być dostępne, oraz są to małe grafiki to drawable. Jeśli mają to być duże obrazy statyczne, to wrzuć raczej do assets jako pliki i wczytuj w programie też jako pliki (przez URI). A jeśli obrazy dynamiczne, to powinny leżeć w systemie plików: w cache lub przestrzeni prywatnej aplikacji (wtedy będą dostępne tylko dla twojej aplikacji) - ale cache użytkownik może wyczyścić, albo gdzieś na karcie SD (np jeden ze standardowych folderów DCIM, PICTURES etc),a w bazie tylko odwołania do nich.

Wpychanie takich wielkich danych bezpośrednio jako bloby bo bazy to bardzo zły pomysł.

CH
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 miesiące
  • Postów:128
0

Dobra, już opisuję:

Jest to apka, która ma przechowywać "śmieszne" obrazki dla użytkownika, użytkownik może "dokładać"/usuwać (DYNAMICZNIE) obrazki do niej oraz może je przeglądać (RecyclerView)- wnioskuję z Twojej wypowiedzi, że powinienem je przechowywać na SD najlepiej - tylko czy mogę razem z danym zdjęciem przechować np. informację w formie Stringa/Tesktu z jakimś krótkim opisem (ale na razie żeby nie udziwniać wystarczy mi odpowiedź czy SD to w takim wypadku dobry pomysł - jak zaimplementuje to, to potem będę udziwniał)? :/

Pozdrawiam.

1

Odpowiedz sobie na pytanie, czy chcesz zabronić użytkownikowi dostępu do zdjęć na karcie, przez menedżera plików np. Jeśli nie jest to konieczne, to stwórz folder np w PICTURES (tylko nie szukaj tego katalogu na sztywno, jest api do pobierania katalogu PICTURES) i tam przechowuj obrazki. Nic nie powinieneś przechowywać razem z obrazkiem, powinno ci wystarczyć odwoływanie się do obrazków po nazwie pliku.

Lub jeśli obrazki mają być widoczne tylko w twojej aplikacji, to możesz przechowywać w folderze prywatnym twojej aplikacji, reszta się nie zmienia poza tym, że nikt nie wejdzie "z boku" i tych plików np nie usunie albo nie pozmienia im nazw - z druiej jednak strony, wtedy zapychasz miejsce na partycji /data (tej, na której instalowane są wszystkie aplikacje) i rozmiar zainstalowanej aplikacji zaczyna puchnąć, użytkownik widzi tylko tyle, że "dane aplikacji" to coraz więcej i więcej, a na niektórych telefonach na partycji /data jest mało miejsca.

Także, wszystko zależy od tego co chcesz osiągnąć i jak ma to działać

CH
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 miesiące
  • Postów:128
0

Tamto pytanie nie miało sensu, jednak teraz mam zagwozdke... jak najlepiej przechowywać w bazie danych referencje do danego obrazka? Jako ścieżka do niego i przy czytaniu z bazy od razu odczytywać dany obraz?

0

Jeśli już, to nie ścieżka tylko uri

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)